next to the Powershell book previews already metioned (and on the delicious links), I noticed that I did not yet linked to this one yet :
In this free e-book on realtimepublishers.com about PowerShell you can find a good introduction to PowerShell. An Introduction to Microsoft PowerShell by Don Jones
and on the codeproject a nice article about writing a CMDlet to use Copernic Desktop Search (CDS) application from powershell.
PowerShell Tab Completion is since RC1 customizable,
you can look at the current implementation like this :
get-content function:TabExpansion
This is my first customization to this function :
I added Tab-completion for Types to get the static methods (and properties) I like this especialy becouse normaly you have to remember to use get-member - static to list them.
*Note* if you output the original code to a file (gc function:TabExpansion | out-file) you will miss the line "Function {" and the last "}" you need to add it to declare the function again.
then below the Switch statement (I left in in for readability, you add the custom code.
you need to . source the script to overwrite the $global tabExpansion function. and put it in your profile to use it every session.
as I did not convert my out-DataGrid yet (changing MSH to PS in 2 places) I will also provide my version here, the diffence is that I as a Datagrid and Abhiskek did use a array. my version is a bit bigger, but I like the datatable as Greg did notice in the comments the sort in the Datagrid will not work on an array, but does an the datagrid and also that I can combine the data from all kind of sources :(see working with CSV files in MSH (part one) and some of the links or seach for system.data on my blog to find more info.) and as you can see here : MSH GUI Viewer for Dataset Example in some screenshots, so you can walk the relations you did make (only the datagridpart not the converting part for the rest the same as for the old focus hack)
I also have a script using only the convert to dateTable, that I will also post , and the helpers to get a CSV file or a Excel sheet into a dataTable ( some already posted )
so now you have the toolset to get together changed for PowerShell , and you can just past in the whole bunch and get working with CSV file Excel files DataTables and Combining them, and last but not least viewing them in a GUI.
a last remark note that the functions are made for commandline usage, so you dot-source the connect funtions (otherwise csv files or excel sheets are listed but go out of scope after running the function and con not be used) : then the functions just assume and take the connection object ($con or $xlsCon) as i explained in former posts.
so you work like this :
# takes directory name as parameter CSV and TXT files in directory are tables.
. connect-csv c:\Csvfiles
# takes Excel filename as parameter Sheets are datatables
. connect-Excel c:\ExcelFiles\file.xls
# after connecting you can just use the get-* functions
# get CSV file
$file = get-DataTable file#csv
# get XlsSheet (defaults to sheet1$ )
$file2 = get-xlsSheet
# make new dataset
$ds = new-object System.Data.dataSet
# merge the files
$ds.merge($file) $ds.Merge($file2)
# show in GUI (no parameter just assumes there is a $ds object ;-) )
show-DataSet
# out-dataTable will convert command output to a dataTable ( you can merge again in the $ds)
$dt = gps | out-dataTable
and here are the updates and utility scripts : (note most parts are formerly posted on my blog and origional entrys contain more information about the workings, so if things are not clear try the links)
# Function out-datagrid # shows piplineinput in a GUI using a datagrid # /\/\o\/\/ 2006 # http:mow001.blogspot.com
As most where mentioned before and not all had to be changed I still reposted them all as I hope this combination of scripts helps to see the complete picture of combining data in PowerShell using ADO (the samples are not complete as you can add Access and SQL also to the toolkit as you can see in other entries, but that a leave up to you to make the post not even bigger)
but I mean that you can just past all the code into your PowerShell console, pick a directory that contains CSV files ans an Excel sheet and follow the examples above and in the other posts and get experimenting.
also be sure the check the select samples in the CSV series to create new combined datasets and working with export-csv to safe them. and follow the post about how to make relations and then use Show-DataSet again and see how you can walk the relations.
I use this a lot comparing information from different sources.
let me know what you think of this way to work with data in Powershell
(new-object Management.ManagementObjectSearcher('associators of {Win32_Directory.Name="c:\\foobar"} where assocclass = Win32_SubDirectory role = GroupComponent')).get()
But how did I come to those ?
As I did say before I showed the wrong workaround in the first, the Management.RelatedObjectQuery helps with this task so following and using the 2 former posts :
but as working with relations is an advanced WMI topic, and the former Service example used another kind of relation, I will show how I came to the query in this case.
I came to this using the commandline like this :
first get some info using the getrelationships() method :
(new-object Management.ManagementObjectSearcher('associators of {Win32_Directory.Name="c:\\foobar"} where assocclass = Win32_SubDirectory role = GroupComponent')).get()
now that you can see parameters like this the overload in not that hard do, just fill in what you know.
You see using the .NET system.management helper classes and out-propertyGrid can make this task a whole bit easier. just copy the properties of $roq or just use it.
Pete did ask 3 questions in the comments of the last post. I think they were interesing enough to make a new post,
first about using $name and just the string of the directoryname,
as I made commandline examples I did just type in the string, and did $name = 'c:\foo' as you would do that in the Share example (it would be the path of the share there, i give that example in the NG I think.) I just mixed it up in the examples by acident sorry if that was confusing.
but for the second question how to handle the escapingm if you get back a path without the escaping you can use the replace method.
$_.name.replace('\','\\')
you can see how I used it in the recursive sample below
and the last question, about recursion, we can make a recursive function in PowerShell to get all the subdirectories, in the sample below the function does just call itself again for each subdirectory found. so that it wil recurse the complete subtree.
# recursive directory iterating using wmi Function get-DirTree ($name) { (gwmi Win32_directory -filter"name = '$name'").getrelated('Win32_directory') | where {$_.name -match $name} |% { $_.name get-SubDirs $_.name.replace('\','\\') } }
In the new Microsoft.Public.Windows.PowerShell NewsGroup (we where shareing m.p.w.server.scripting), In the Thread : gwmi to get folder and security info :
A good reason for this is that you want to do it remote, another reason he rewrote this was that he did not like use SDDL (no reason for using WMI as it would be also possible using the directorytree example ), but lets focus on the WMI and get subdirectory part
the (gwmi Win32_directory -filter "name = 'c:\\foobar'").getrelated() Method will get all the related classes, you can see that this includes all the directories that are related and also the Win32_LogicalFileSecuritySetting class (very hande as we needed that also.
to get all the relations as a WMI class use the GetRelationships Method (gwmi Win32_directory -filter "name = '$name'").GetRelationships()
but there are 2 problems left first we need to split the security and the subdirectory info that is easy :
but we also get the parent directory, a diffence is that in this case the find directory is the GroupComponent part,
GroupComponent : \\CP340339-A\root\cimv2:Win32_Directory.Name="c:\\" we can filter on the GroupComponent but its hard to type (with all the escaping) But we can make use of some helperclasses for making the combined query.
it's from october last year so using Monad V2 but this is not changed much. if you need to make more difficult WMI queries I think it still worth reading.
only to make the query in a GUI, I made an updatedversion that also takes pipelineinfo :
as I did a more detailed explainatin in that post I will not go into that,
but I will use a simpler workaround in Monad here : I just pipeline it to a where and check if the Path of the directories found contains the name of the current directory, if not it must be the root.
so you can see that the WMI relations are very handy in this case to get from a directory to the directorysecurity and also gives a way to iterate subdirectories using WMI.
I hope this commandline examples make clear how this could help makeing the directoryscript using WMI.
On my blog as I provide samples, I most of the time keep them as simple as possible, without errorhandling or parameterchecking etc.I just focus on the target
as in the temperature converter function examples in last post,
I did them as one-liners without any checking to keep it simple.
Jeffrey Snover, was so kind to leave a variation in the Comments, that does give usage info if you do not give a parameter (see example 2 below), mine would just convert 0 (see example 1 below)
this makes the script a bit more userfriendly, but what if a string is given ?
FooFoo32 ?
hmm, we should better catch that also then ...(that is why I let them out most of the time, to keep focussed at the "real" example ;-), but ok lets provide 2 other variations now, to make it up)
one way is to give typeinfo data to the parameter, so that this is checked by the function, (see example 3 below)
so we also did catch wrong parameters now. but this does not give the usage information,
so I did another veriation, in the last example, I removed the typeinfo to the parameter and used a Trap Statement, to provide the UsageInformation.(see example 4 below)
in the samples below I will show the different version and what does happen with different kinds of (wrong) input :
Examples :
# Example 1 # My old Function :
function ConvertTo-Celsius ($Fahrenheit) {($Fahrenheit - 32) / 1.8}
# example
MowPS>ConvertTo-Celsius 77 25
# if you not specify a parameter $null -> 0 is calculated :
MowPS>ConvertTo-Celsius -17.7777777777778
# example 2 : # Jeffrey Snover 's variation with some errorhandling
MowPS>ConvertTo-Celsius USAGE: ConvertTo-Celsius -Fahrenheit degrees At line:1char:57 + function ConvertTo-Celsius ([decimal]$Fahrenheit=$(Throw <<<< "USAGE: ConvertTo-Celsius -Fahrenheit degrees")) {
MowPS>ConvertTo-Celsius foo ConvertTo-Celsius : Cannot convert value "foo" to type "System.Decimal". Error: "Input string was not in a correct format." At line:1char:18 + ConvertTo-Celsius <<<< foo
MowPS>ConvertTo-Celsius 77 25.0
# Example 4 : # an other variation giving a custom message using TRAP :
hope this examples help in adapting other examples to scripts with some errorchecking, (so lazy me can leave them out in my samples and say it is for readability ;-))
For more information about errorhandling and debugging in powershell see also this 7 part series on the PowerShell team blog about it : Debugging Monad Scripts, Part 7 (Final): How Traps Work(links to all former parts are in this post)
but there is a more native way to do this on PowerShell,
*edit* but as Jacques (links to French blog janel) pointed out to me in the comments, this is only valid for the PowerShell so you can not use it to map a drive and use it from the CMD prompt or the GUI (what is a big difference ) but if you use it in the powershell it has a lot of power as naming the drive with more letters, a path, or mapping to a registrykey.
New-PSDrive HKCR Registry -root HKEY_CLASSES_ROOT
or a registry path e.g. the PowerShell configuration
as PowerShell gets his own newsgroup I things will get a bit better, as we also have to think about it that we are still "sharing" the NG with the other Server scripting languages, so not everybody is asking for the PowerShell posts also.
it does stay a difficult question, as I also remember how it was when I started with Monad, l but I still would recommed to follow microsoft.public.windows.server.scripting and later microsoft.public.windows.PowerShell as it still is a great source to get PowerShell info, and support. b.t.w. I did see a discusion like this before in the comments on Lee Holmes blog before about what to post on his blog, Question: Do you _not_ read the newsgroup?
what do you think about Newsgroups comparing other forms like the docs, Blogs, Sites, IRC ?
While and after writing the PowerShell Export and Import shares scripts I got questions on how to do this for Directory Security in the NG thread that started me writing those 2 example scripts (Security and monad) ,
and I also got a comment from Pete Gomersall on the latter post, about doing this for Directories and recursing.
I already provided some info about win32_directory and the get-acl CDMlet in the Thread.
but I decided to write some example scripts for that also, but this Time I will not use WMI but the get-acl and set-acl commandlets.
Also I save the Security info in SDDL (Security Descriptor String Format) form to make the CSV file smaller, as Directories most of the time have much more and detailed ACL's as a Share does.
(Note that SDDL does support "GA" GENERIC_ALL opposed to the .NET Enum see NG thread)
The provided scripts work like this :
MowPS>Export-DirTee c:\foobar
Dir SDDL --- ---- c:\foobar O:S-1-5-2
MowPS>Export-DirTee c:\foobar -r
Dir SDDL --- ---- c:\foobar O:S-1-5-2 C:\foobar\Bar O:S-1-5-2 C:\foobar\Foo O:S-1-5-2
MowPS>Export-DirTee c:\foobar -r | fl
Dir : c:\foobar SDDL : O:S-1-5-21-
Dir : C:\foobar\Bar SDDL : O:S-1-5-21-
MowPS>Export-DirTee c:\foobar -r dirSec.csv
Exporting to dirSec.csv
MowPS>rd c:\fooBar
Confirm
The item at C:\fooBar has children and the -recurse parameter was not specified. If you continue, all children will be removed with the item. Are you sure you want to continue? [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): a
# all Directories are gone now :
MowPS>Export-DirTee c:\foobar -r
Path "c:\foobar" Not Found
# Let re-Import Them :
MowPS>Import-dirTree dirSec.csv Creating c:\foobar Setting Security on : c:\foobar
Creating C:\foobar\Bar Setting Security on : C:\foobar\Bar
Creating C:\foobar\Foo Setting Security on : C:\foobar\Foo
# and Yes the Security is back also :
MowPS>Export-DirTee c:\foobar
Dir SDDL --- ---- c:\foobar O:S-1-5-21-
MowPS>Export-DirTee c:\foobar -rec
Dir SDDL --- ---- c:\foobar O:S-1-5-21- C:\foobar\Bar O:S-1-5-21- C:\foobar\Foo O:S-1-5-21-
Note that this will not keep any files and does not touch the security on them, the Import script will just create the Directories if they do not exist and set the security on them, any existing files will not be touched, and will keep the current security.
and here the scripts :
# export-dirTree # # this Function will Export a directory Tree # complete with securityInfo to CSV # # /\/\o\/\/ 2006 # http://mow001.blogspot.com
Function Export-DirTree ($path,[switch]$recurse,$Outfile) { if (Test-Path($path)) { $DirInfo = @() $DirInfo += $path | select @{e={$_};n='Dir'}, @{e={(get-acl $_).sddl};n='SDDL'} if ($recurse.IsPresent) { ls $path |? {$_.PsIsContainer} |% { $DirInfo += $_ | select @{e={$_.fullname};n='Dir'}, @{e={(get-acl $_.fullname).sddl};n='SDDL'} } }
if ($outFile){ write-host "Exporting to $outFile" $DirInfo | export-csv $outFile }Else{ $DirInfo }
}Else{ write-host "Path `"$path`" Not Found" }
}
# Import-DirTree # # This Function will Import the directories from a CSV file # made by Export-DirTree function complete with securityInfo # # /\/\o\/\/ 2006 # http://mow001.blogspot.com
LastName FirstName Department HireDate -------- --------- ---------- -------- Myer Ken Finance 3/1/200612:00:00 AM Ackerman Pilar Finance 3/1/200612:00:00 AM
in this case you see that it does not matter much, and for the ADO example I need 2 helper functions and it is outputting more or less doing the same, but in the second example I have the power of the .NET dataset and can make relations etc
as we only can create the share one time but there could me more entries for a share in the script I loop only trough the shares on the commandline it looks like this :
Name Path Description ---- ---- ----------- Bar C:\Bar Foo C:\Foo
you can see how get a list with every share only one time, so I can loop trough it to make the shares.
for each share in the loop I find only the rows of the second share and I do another loop (on the commandline Example I hardCoded Bar)
MowPS>$sharelist |? {$_.name -eq 'bar'}
Name : Bar Path : C:\Bar Description : User : Everyone Domain : Computer SID : S-1-1-0 AccessMask : 1179817 AceFlags : 0 AceType : 0
Name : Bar Path : C:\Bar Description : User : Mow Domain : Computer SID : S-1-5-21-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-xxxx AccessMask : 2032127 AceFlags : 0 AceType : 0
Next I need to convert the textform SID into a Binary SID again, therefore we can use the securityidentifier .NET class ( for more info see : Get Binary SID in MSH (Share Security Update))
this is becouse there is a AliasProperty Name Defined that overrules the Original Name property of the win32_trustee Class in the typedata of PowerShell RC1, I will file this as a Bug on Connect.
the calling of the create method I did from an template I did create with the get-WmiMethodHelp script from this post : MSH get-WmiMethodHelp function Update 3 and did fill in.
note the use of $sd.PsObject.BaseObject (if you forget this PowerShell will give a confusing error)
The Complete script looks like this :
# ImportShares.ps1 # This script will Import the Shares from a CSV file # made by ExportShares.ps1 complete with securityInfo # # /\/\o\/\/ 2006 # http://mow001.blogspot.com
# and Yep this looks right, the seurity is back also.
you can see the shares are recreated with the right securitym and a return value is returned to check if it want OK (a 0 means OK a 22 share does exist allready).
if you want to know the other returnvalues you can look at the get-WmiMethodHelp script output also :
The Create method initiates sharing for a server resource. Only members of the Administrators or Account Operators local group or those wit h Communication, Print, or Server operator group membership can successfully execute Create. The Print operator can add only printer queues . The Communication operator can add only communication device queues. The method returns an integer value that can be interpretted as foll ows: 0 - Successful completion. 2 - The user does not have access to the requested information. 8 - Unknown failure. 9 - The character or file system name is invalid. 10 - The value specified for the level parameter is invalid. 21 - The specified parameter is invalid. 22 - The share name is already in use on this server. 23 - The operation is invalid for a redirected resource. The specified device name is assigned to a shared resource. 24 - The device or directory does not exist. 25 - The share name does not exist. Other - For integer values other than those listed above, refer to Win32 error code documentation.
PS. as Blogger had problems and my first post failed my post is messed up by BLogger, so the formatting is messed up and you may miss some pipeline symbols (and and of lines when pasting, sorry for that, but I RePasted the complete script again into the post so that should not give problems when pasted in the the powerShell