Quantcast
Channel: Scripting Blog
Viewing all 2129 articles
Browse latest View live

Weekend Scripter: Use PowerShell to Create Folder

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create folders.

Microsoft Scripting Guy, Ed Wilson, is here. I am not a huge fan of using a mouse. In fact, the more things I can do from Windows PowerShell the better. It is a huge waste of time for me when I have to remove my hands from the keyboard, chase down a mouse, mouse around for a while, and then return my fingers to the home row on the keyboard. One cool thing is that Microsoft Word has a number of keyboard shortcuts—of course, it also has an API. I also do quite a bit of scripting for that.

Another place where I use Windows PowerShell quite a bit is for creating folders, directories, or containers (whatever we are calling them this week). I know that Windows creates lots of default folders, but they seem to be buried in my profile, and they are not all that accessible. I prefer to create my own directory structure to make it easier to copy, back up, and to use from within a Windows PowerShell script or console.

Something I often see is that scripters test for the existence of a folder, then if the folder does not exist, they create it. Here is a typical form of this code:

$path = "c:\fso"

If (Test-Path -Path $path -PathType Container)

    { Write-Host "$path already exists" -ForegroundColor Red}

    ELSE

        { New-Item -Path $path  -ItemType directory }

Although the previous code works, it is an awful lot of work. One might decide to add this as an ISE script snippet to simplify the coding process.

But what is the purpose of the code? Most of the time, the purpose is to avoid an error message that occurs when creating a folder that already exists. If this is the purpose of writing such code, you can avoid the error message by using the –Force parameter. Here is an example:

New-Item -Path c:\fso1  -ItemType directory -Force

In the following image, I run this command twice. Note that no error occurs.

Image of command output

I can use the New-Item cmdlet to create a nested folder—even if the root folders do not exist. This is shown here:

$path = "c:\fso3\fso3\fso3\fso3"

Remove-Item $path -Recurse -Force

New-Item -Path $path  -ItemType directory -Force

My favorite way to create a new folder is to use the MKDIR function (MD is an alias for MKDIR). MKDIR is cool because it already knows that I want to make a folder, and so I can skip that parameter. I can also specify an array of folder names in the function. I can specify the –Force parameter to keep the command from generating errors if a folder already exists. Here is an example:

$path = "C:\fso","C:\fso1","C:\fso2"

md $path -Force

The command and its output are shown here:

Image of command output

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Find if Folder Exists

$
0
0

Summary: Use Windows PowerShell to see if a folder exists.

Hey, Scripting Guy! Question How can I easily find if a folder exists for a Windows PowerShell script that I am writing?

Hey, Scripting Guy! Answer Use the Test-Path cmdlet and the PathType parameter, for example:

Test-Path c:\fso -PathType Container

Use PowerShell to Create ZIP Archive of Folder

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create a .zip archive of a folder.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need a way to create a .zip archive of a folder. I would like to do this on my laptop running Windows 8.1, and I do not want to install any other software. Can I do this?

—TR

Hey, Scripting Guy! Answer Hello TR,

Microsoft Scripting Guy, Ed Wilson, is here. The weed eater dude is outside. The guy is really dedicated to his job. I mean, the snow has barely cleared, and he is out there chopping away with his weed eater. I really enjoy hearing him, because it fills me with hope that summer is on its way, and that soon we will have warm weather and we can get outside without having to bundle up.

Certainly I can put on a coat and hop on my bicycle, but I learned (the hard way) a long time ago that trying to ride a bicycle when there is ice on the road is not the smartest thing to do (at least not for me). So I prefer to wait until the snow melts, the ice thaws, and the sun is out before taking to the open road.

TR, luckily, you do not need to wait for anything before you can use Windows PowerShell to create a .zip archive. You have everything you need—and that is .NET Framework 4.5.

The ZipFile .NET Framework class was introduced with .NET Framework 4.5, and Windows 8.1 ships with .NET Framework 4.5 installed. This is really cool because this class is extremely easy to use.

The ZipFile class is not available by default in Windows PowerShell because the System.IO.Compression.FileSystem assembly is not loaded by default. Therefore, I want to load the assembly. The best way to do this is to use the Add-Type cmdlet and specify the name of the assembly as an argument to the –Assembly parameter. This is the command:

Add-Type -assembly "system.io.compression.filesystem"

The ZipFile .NET Framework class has a static method named CreateFromDirectory. This method accepts two arguments: a source directory and a destination file. The source directory and the destination file cannot reside in the same directory. This is due to file locking, and it will generate the following  error message:

Image of error message

When you are using this method, if the file archive file already exists, the following error message appears:

Image of error message

To fix this issue, I add a Test-Path command to delete the archive file if it already exists. This is shown here:

If(Test-path $destination) {Remove-item $destination}

The CreateFromDirectory method is easy to use. It is a static method, so I can access it directly from the ZipFile class. Also it takes two arguments, Source and Destination, so the method call makes sense. Here is the command I use:

[io.compression.zipfile]::CreateFromDirectory($Source, $destination)

For the complete script, I add Source and Destination as variables at the beginning of the script. Remember, Source is a directory and Destination is a file that will hold my .zip archive. Here is the complete script:

$source = "C:\fso"

$destination = "C:\fso1\FSO_Backup.zip"

 If(Test-path $destination) {Remove-item $destination}

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::CreateFromDirectory($Source, $destination) 

Now when I run the script, an archive appears in my destination folder. The archive contains all of the files from the source. This is shown here:

Image of folder

TR, that is all there is to using Windows PowerShell to create a .zip archive of a folder. ZIP Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find ODBC Drivers

$
0
0

Summary: Use Windows PowerShell to find installed ODBC drivers.

Hey, Scripting Guy! Question How can  I use Windows PowerShell to check installed ODBC drivers so that I can investigate if a missing
           driver might be the cause of a database application that appears to be failing?

Hey, Scripting Guy! Answer Use the Get-OdbcDriver function from the WDAC module, for example:

Get-OdbcDriver | Format-Table name, platform -AutoSize

Use PowerShell to Zip Multiple Folders

$
0
0

Summary: Use Windows PowerShell to create a .zip archive of multiple folders.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to compress multiple folders before I attempt to archive them. I would like to do this without having to install additional software. Can you help?

—DR

Hey, Scripting Guy! Answer Hello DR,

Microsoft Scripting Guy, Ed Wilson, is here. This afternoon I am sipping a red berry tea and munching on a chocolate biscotti. Maybe it is not too exciting, but it is relaxing. I am looking over my email sent to scripter@microsoft.com on my Surface 3 Pro, and things are good.

One of the cool things about the free update to Windows 8.1 from Windows 8 is that in addition to including Windows PowerShell 4.0, it includes .NET Framework 4.5, which is way cool. The thing I love the best is the improved compression classes. It makes working with .zip files a piece of cake.

I have a folder on my laptop that I use for backing up files, creating archives, and stuff like that. So, I do not need to check to see if a folder exists or worry about overwriting such a folder. Here is the path assignment in my script:

$path = "C:\backup"

I use the Get-ChildItem cmdlet to find all of the folders I want to archive. In this example, I want to archive all of my FSO* types of folders. I test my command before I add it to my script. This is the command and its output:

PS C:\> Get-ChildItem -Path c:\ -Filter "fso?" -Directory

    Directory: C:\

Mode                LastWriteTime     Length Name                                      

----                -------------     ------ ----                                      

d----          3/4/2015   9:47 AM            fso                                        

d----          3/9/2015   3:28 PM            fso1                                      

d----          3/9/2015   3:28 PM            fso2                                      

d----          3/9/2015   3:28 PM            fso3       

The cool thing is that in the Windows PowerShell ISE, I can highlight only the portion of the command I want to use, and that is what runs. So my actual command will be:

$source = Get-ChildItem -Path c:\ -Filter "fso?" -Directory

I know that this returns a DirectoryInfo object, and that I need to access specific properties to get to the individual folder paths—but I will do that later.

I need to add the assembly that contains the compress classes, so I do this here:

Add-Type -assembly "system.io.compression.filesystem"

I now need to create the destination path for each archive I will create. I do this inside a loop that walks through my collection of DirectoryInfo objects. This script is shown here:

Foreach ($s in $source)

 {

  $destination = Join-path -path $path -ChildPath "$($s.name).zip"

I keep only one archive of a folder in my Backup folder at a time, so if the archive exists, I want to delete it. Here is the script that accomplishes that task:

If(Test-path $destination) {Remove-item $destination}

Now it is the simple task of creating the archive. Here is the command:

[io.compression.zipfile]::CreateFromDirectory($s.fullname, $destination)

The complete script is shown here:

$path = "C:\backup"

$source = Get-ChildItem -Path c:\ -Filter "fso?" -Directory

Add-Type -assembly "system.io.compression.filesystem"

Foreach ($s in $source)

 {

  $destination = Join-path -path $path -ChildPath "$($s.name).zip"

  If(Test-path $destination) {Remove-item $destination}

  [io.compression.zipfile]::CreateFromDirectory($s.fullname, $destination)}

I check to see if the archives exist. As shown in the following image, they do:

Image of folder

DR, that is all there is to using Windows PowerShell to create a .zip archive of multiple folders. Zip Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Map a Drive

$
0
0

Summary: Learn how to use Windows PowerShell to map a drive.

Hey, Scripting Guy! Question How can I use Windows PowerShell  to map a drive to a server from a client running Windows 8.1?

Hey, Scripting Guy! Answer Use the New-SmbMapping cmdlet and specify the local path and the remote path, for example:

New-SmbMapping -LocalPath h: -RemotePath \\dc1\Share

Use PowerShell to Extract Zipped Files

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to extract zipped files.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to be able to work with zipped files from time-to-time. Often I store files in a zip archive so they are portable. I know how to copy the .zip archive from one place to another with Windows PowerShell, but I cannot seem to figure out how to unzip the archive. Can you help me? I would be ever so grateful.

—SK

Hey, Scripting Guy! Answer Hello SK,

Microsoft Scripting Guy, Ed Wilson, is here. This morning I got out my bag of expresso beans and set up my rotary bean grinder. I am thinking I will make some expresso this afternoon…or maybe tomorrow afternoon. I have an old-fashioned, stovetop, double-boiler. It is like one I bought a long time ago when I was in Naples, Italy. It is ridiculously simple, and does an excellent job. I put the water in the bottom and super finely ground beans in the middle, and after a short time, the expresso appears in the top. The only trick is ensuring that I get the right amount of water in the bottom.

I sometimes also make cappuccinos on Saturday mornings, and I have a hand milk frothier that I use for that. I love using manual tools when I have time, or when I want to take time for an exceptional occurrence. However, for things that occur more than once or twice a month, I want to automate them—big time. Maybe one day, someone will invent a PowerShell powered teapot.

To extract all files from a .zip archive file, I use the ExtractToDirectory static method from the [io.compression.zipfile] .NET Framework class. To use this class, I need to add the System.IO.Compression.FileSystem assembly to my Windows PowerShell console or to the Windows PowerShell ISE.

To add the assembly, I use the Add-Type cmdlet and specify the –Assembly parameter. This command is shown here:

Add-Type -assembly "system.io.compression.filesystem"

The command to extract the zipped files to a folder is:

[io.compression.zipfile]::ExtractToDirectory($BackUpPath, $destination)

Here are a few things to keep in mind:

  1. The first parameter I call ($BackUpPath)must point to a specific zipped file.
  2. The second parameter (the one I call $destination) must point to a folder.
  3. Both of these parameters are strings. Therefore, I cannot use a ziparchive object or a directoryinfo object as input types.
  4. The extraction does not include the root folder.

My complete script is shown here:

$BackUpPath = "C:\backup\fso.zip"

$Destination = "C:\recovered"

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::ExtractToDirectory($BackUpPath, $destination)

When I go to my C:\recovered folder, I see that all of the files from the fso.zip folder are now present.

SK, that is all there is to using Windows PowerShell to extract zipped files. Zip Week will continue tomorrow when I will talk about zipping and emailing an archived folder.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Copy Source to Multiple Destinations

$
0
0

Summary: Use Windows PowerShell to copy a source directory to multiple destinations.

Hey, Scripting Guy! Question How can I use Windows PowerShell to make multiple backup copies of a source directory without wasting a
           lot of time mousing around?

Hey, Scripting Guy! Answer Copying a single source directory to multiple destinations can be a single line command, for example:

"c:\fso1","c:\fso2","c:\fso3" | % {Copy-Item c:\fso -Recurse -Destination $_}

Note  The % symbol is an alias for the Foreach-Object cmdlet.


Use PowerShell to Create Archive and Send Email

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to create a .zip archive and email it.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a number of files that I would like to archive on a regular basis to a .zip file. I need to email that .zip file as an attachment. I do this every week, and it takes me like nearly 15 minutes to create the .zip file, open Outlook, squirrel around and find the file, write the email, send the thing, and then delete the .zip archive from disk. If I could run a script, it would save me over an hour a month—that is nearly two days of free labor. Can you do it?

—JB

Hey, Scripting Guy! Answer Hello JB,

Microsoft Scripting Guy, Ed Wilson, is here. Today I am sipping a nice cup of Earl Grey tea with a cinnamon stick in it. I was talking to my old high-school friend last night. He is heading to Raleigh to see a concert, and he thought it would be cool to get together on his way through Charlotte. Unfortunately, we will be on the coast when he comes floating by. Oh well. Hopefully, we will get together again soon. It is nice to keep up with friends, even when they don’t provide much heads-up before they want to stop by.

The cool thing about using Windows PowerShell to automate creating .zip archives and emailing them is that it is easily scripted. In fact, it can easily be turned into a scheduled task if one wishes to take the next logical step.

The first thing to do is to create a .zip archive of the folder that contains the files that you want to archive. I like to create two variables: one for the source files and one for the destination that will hold the .zip archive of the files. I then use the Test-Path cmdlet to ensure the archive file is not already there, and if it is, I delete it. This prevents error messages. Here is the first three lines of my script:

$source = "C:\fso"

$destination = "C:\backup\FSO_Backup.zip"

 If(Test-path $destination) {Remove-item $destination}

Now I need to add the assembly that contains the compression classes from .NET Framework 4.5. To do this, I use the Add-Type cmdlet, specify that it is an assembly, and provide the name System.IO.Compression.Filesystem to it. This command is shown here:

Add-Type -assembly "system.io.compression.filesystem"

The final command creates the .zip archive. It uses the CreateFromDirectory static method from the ZipFile class:

[io.compression.zipfile]::CreateFromDirectory($Source, $destination) 

This section of the script is shown here:

$source = "C:\fso"

$destination = "C:\backup\FSO_Backup.zip"

 If(Test-path $destination) {Remove-item $destination}

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::CreateFromDirectory($Source, $destination) 

Now I need to email the archive. To do this, I use the Send-MailMessage cmdlet. This cmdlet can do all sorts of stuff, but for our purposes, I need to add the To and From parameters, the attachment path, the subject, and the body message.

This is all pretty simple. I also need to specify the appropriate SMTP server for my mail application, and specify if I need to use credentials or SSL. It may take a bit of practice or research to get everything working perfectly. But when it is done, well, it is done. Here is the command I use:

Send-MailMessage -From "ScriptingGuys@Outlook.com" -To "ScriptingGuys@Outlook.com" `

 -Attachments $destination -Subject "$(Split-Path $destination -Leaf)" -Body "File attached" `

 -SmtpServer "smtp-mail.outlook.com" -UseSsl -Credential "ScriptingGUys@Outlook.com"

The last requirement is to clean up by deleting the previously created .zip archive. This is simple. I use a Remove-Item command that uses the $Destination variable:

Remove-Item $destination

The complete script is shown here:

$source = "C:\fso"

$destination = "C:\backup\FSO_Backup.zip"

 If(Test-path $destination) {Remove-item $destination}

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::CreateFromDirectory($Source, $destination)

Send-MailMessage -From "ScriptingGuys@Outlook.com" -To "ScriptingGuys@Outlook.com" `

 -Attachments $destination -Subject "$(Split-Path $destination -Leaf)" -Body "File attached" `

 -SmtpServer "smtp-mail.outlook.com" -UseSsl -Credential "ScriptingGUys@Outlook.com"

 Remove-Item $destination

JB, that is all there is to using Windows PowerShell to create a .zip archive and to email it off.  Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Easily Find PowerShell DSC Resources

$
0
0

Summary: Use Windows PowerShell to easily find DSC resources.

Hey, Scripting Guy! Question How can I find what Desired State Configuration (DSC) resources are installed on my local system?

Hey, Scripting Guy! Answer Use the Get-DSCResource cmdlet.

PowerTip: Use PowerShell to Check for Snapshots

$
0
0

Summary: Learn how to use Windows PowerShell to check for virtual machine snapshots.

Hey, Scripting Guy! Question How can I use Windows PowerShell to see if a particular virtual machine has snapshots?

Hey, Scripting Guy! Answer Use the Get-VMSnapshot cmdlet, for example:

Get-VMSnapshot dc1_nwt

Note  This cmdlet requires running an account that has admin rights.

Optimize PowerShell Code?

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about optimizing Windows PowerShell code.

Microsoft Scripting Guy, Ed Wilson, is here. I was looking at my Windows Phone this morning and I noticed that today is Friday the 13th. What seemed a bit strange to me is that I thought there was also a Friday the 13th last month. I then became curious. Exactly how often does the 13th of the month fall on a Friday? Or put another way, how many Friday the 13th’s are there in a year—or at least for this year?

Perhaps I could have opened the Internet and used a Bing search to find out, But I was fairly certain that whatever search terms I used would return lots of stuff about certain movies that I really did not want to think about first thing in the morning…especially today. In any event, I am pretty good with writing Windows PowerShell code, so it took me less than two minutes to whip up a bit to return the answer.

The first thing I did was use the For statement to count from 1 to 12 in increments of 1:

For($d = 1; $d -le 12; $d++)

Next, I created a date using my $d variable:

$datetime = [datetime]"$d/13/15"

If the DayOfWeek property matches Friday, I want to display the date. This is shown here:

If($datetime.dayofweek -match 'Friday')

     { $datetime }

So that is it—as you can see here, four lines of code:

For($d = 1; $d -le 12; $d++)

{

  $datetime = [datetime]"$d/13/15"

  If($datetime.dayofweek -match 'Friday')

     { $datetime }}

When I run the script, the following output appears in the output pane of my Windows PowerShell ISE:

Image of command output

Optimize the code

I decided to ask a few people if they could optimize my code. You see, I did not spend any time at all trying to improve or optimize it. The first to respond was Microsoft PFE, Gary Siepser. He came back with the following:

((1..12).foreach({[datetime]"$_/13/15"}).where({$_.dayofweek -match 'Friday'}))

Gary uses the .Foreach and .Where methods from Windows PowerShell 4.0 to create one monster command. His own remark is, “It is uglier, but at least it is one line.”

He then goes on to say that he did not really understand what I meant when I asked him to “optimize” the code. Did I mean for performance or for simplicity? (I actually think my code is elegant.)

And that was part of my point. I wanted to see what different people automatically think of when we talk about optimization. There are several things that could be thought of as inherent in code optimization:

  • Readability
  • Performance
  • Conciseness

Next to respond was Microsoft PFE, Ashley McGlone. He also sent back a one-line command. Here is his result:

1..12 | % {If (([datetime]"$_/13/15").DayOfWeek -eq 'Friday') {[datetime]"$_/13/15"}}

In Ashley’s example, he stayed with the If statement, but he converted to using the pipeline to create an array of numbers. His code was six characters longer than Gary’s. One big difference between the code from Ashley and Gary may be in terms of readability. Because Gary uses the syntax from Windows PowerShell 4.0, it might not be as readable to some as Ashley’s might be. Also Ashley uses the pipeline, but Gary does not.

Microsoft PFE, Jason Walker, was the next to return an answer. His is the shortest so far—by a long shot, his command is only 63 characters long. How does he do it? Here it is:

1..12 | %{[datetime]"$_/13/15" | Where DayOfWeek -eq 'Friday'} 

Jason uses the pipeline like Ashley did, but instead of imbedding an If statement, Jason pipes the date to the Where-Object cmdlet. This ends up with a command that is a lot shorter.

Microsoft senior SDE, Lee Holmes, also returned an answer. He took the same approach as Jason, but his command was two characters shorter. How did he do that? Well, when making a comparison to the day of the week, he realized that the quotation marks are not required around the word Friday. Here is his answer:

1..12 | % { [DateTime] "$_/13/15" } | ? DayOfWeek -eq Friday

Optimized code summary

All of the code returned exactly the same results. This is shown here:

Image of command output

So which is fastest? I can determine that by using the Measure-Command cmdlet. Here are the results:

Image of command output

One thing to keep in mind is that millisecond results are not accurate for Measure-Command. Also, each time I ran the code, I obtained a different result. What did not change was the order of the results: Gary, Ashly, Lee, and then Jason.

What was really interesting was that although Jason’s and Lee’s one-liners were nearly identical, Jason’s code always showed up as being nearly twice as slow as Lee’s. The only difference was spaces, quotation marks, and aliases. Strange.

And my script? Well, as shown here, it showed up as the fastest of all:

Image of command output

… that is, until I got Bruce Payette’s submission.

Obviously, I emailed a whole bunch of people and asked them to “optimize” the code. Windows PowerShell MVPs, Jim Christopher and Sean Kearney, used the same approach that Lee and Jason used. Here are their samples:

Jim Christopher:

1..12| % {[datetime]"$_/13/15"} | where dayofweek -match 'friday'

Sean Kearney:

1..12 | foreach { [datetime]"$($_)/13/15" | where { $_.DayOfWeek -match 'Friday' }}

Gary wrote me that he showed the optimization question to the Windows PowerShell class he was teaching this week, and one of his students came up with the following. It is a way cool approach:

1..12 | select @{name="FF";Expression={[datetime]"$_/13/15"|? dayofweek -like 'F*'}} -Unique

Microsoft PFE, Brian Wilhite, saw several of the responses to the question in the email thread, so he opted for a different approach for the sake of being different. (By the way, his command was not as fast as Gary Siepser’s.) Here is his script:

$Date = Get-Date 1/1/15

    while ($Date.Year -eq 2015) {

        If (($Date.DayOfWeek -eq 'Friday') -and ($Date.Day -eq 13)){

            $Date

        }

        $Date = $Date.AddDays(1)

    }

Microsoft principal SDE, Bruce Payette, took a completely different approach. He used a ForEach loop instead of the pipeline or the For statement:

foreach ($m in 1..12)

{

    $dt = [datetime]"$m/13/15"

    if ($dt.dayofweek -match 'Friday') { $dt }

Bruce explains that a Foreach loop is faster than the For statement or the pipeline. He goes on to say, “Alternatively, you could use the Foreach/Where method operators to do something like the following:

(1..12).foreach{[datetime]"$_/13/15"}.where{$_.DayOfWeek -eq "Friday"}

This is arguably simpler than his previous script, but it is less efficient due to the script block calls in Foreach and Where.”

When I used Measure-Command on Bruce’s script, he was right—way right. Here is the result:

Image of command output

One of the things I thought was interesting is that many of the people who replied did not even ask what I meant by “optimize.” They just seemed to think “one-liner.” Several people who replied did ask what I meant by optimize—and some even asked if I meant shorter, faster, or more efficient. So what do you think? How would you optimize the code I showed today?

I want to thank all of the people who replied to my email questions and who took the time from their busy schedules to help me optimize this code.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find Day of the Week with PowerShell

$
0
0

Summary: Find the day of the week by using Windows PowerShell.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find what day of the week a particular date falls on?

Hey, Scripting Guy! Answer Access the DayOfWeek property from the DateTime object:

(get-date).dayofweek

Weekend Scripter: Approximate the Value of Pi from a Polygon

$
0
0

Summary: Microsoft senior software engineer, Firaz Samet, shows how to use Windows PowerShell to approximate the value of pi from a polygon.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog post from Firaz Samet in honor of Pi (π) Day. I will turn the blog over…

The Scripting Guy ran across my PowerShell Math Module on CodePlex, and he asked me if I would be interested in writing a blog post for Pi Day. I was also incidentally thinking about Pi Day, so this came at the right time. I hope you enjoy reading it.

First a little bit about me...

I am a senior software engineer at Microsoft where I work on Azure Stream Analytics. I have been playing around with Windows PowerShell since version 1.0 where I worked on SharePoint search management cmdlets. I love the power it provides by accessing the full .NET Framework and its rich set of built-in cmdlets and filtering capabilities. I concede that its syntax needed some time to get used to, but after I went past that, it became a natural way to solve my most common scripting and programming needs. One thing that has always frustrated me is that mathematical notation is a bit cumbersome. One reason I wrote a wrapper around Math.NET is to help ease interactive matrix manipulation.

Pi Day is celebrated around the world on March 3 (3.14). It aims to raise interest in math and especially π. This year’s will be even more significant (3.1415…). For more information, see Pi Day on Wikipedia.

In this post, I will talk about using Windows PowerShell to approximate π with polygons. I will also introduce matrix calculus with Math.NET Numerics, using a thin Windows PowerShell wrapper called Math.NET PowerShell.

Approximating π

The approximation of π that I introduce here starts with a square with sides that measure 2 units. It then approximates the area of the inscribed unit circle (radius is 1 unit, of which the area equals π) by constructing a regular polygon with double the number of sides with each iteration. This is done by chopping off triangles from each corner area, while keeping the apothem to 1.

Image of shapes

By using the triangle properties and the trigonometric half-angle formulae for the tangent, we can deduce the following formula:

Image of equation

Expressing the formula in Windows PowerShell

We now want to express the previous formula with Windows PowerShell. We will mainly use the [math] library’s power method, Pow(x, y). But to make the notation simpler, we will introduce a Windows PowerShell filter to make calling the Pow method closer to the mathematical notation:

filter ^([double] $y){[math]::Pow($_,$y)}

This means that expressing 2³ would look like (2 |^ 3) instead of [math]::Pow(2, 3). Parentheses are still required to prevent the pipeline syntax from affecting the remainder of the code. Similarly,Image of numbers  will become (2 |^ .5).

We now use Windows PowerShell to develop the formula:

function halfTan($t){$t / (((($t |^ 2) + 1) |^ .5) + 1)}

function triangleArea($t){2 * ($t |^ 3) / (-($t |^ 2) + 1)}

 

$t = 1

$t = halfTan $t

$a = ((2 |^ .5) - 1) |^ 2

$p = 4

0..25 | %{

     $i = $_;

     $p-= $a * 4 * (2 |^ $i);

     "{0} t: {1}  a: {2}  ~pi:{3}" -f $i,$t,$a,$p;

     $t = halfTan $t;

     $a = triangleArea $t;

}

On iteration 25, we reach the value of [math]::Pi.

24 t: 2.34066892682746E-08  a: 2.56477909373991E-23  ~pi:3.14159265358979

Matrix expression

The iterative nature ofImage of equationmakes using matrices an interesting proposition. For this reason, we will express it in the following matrix formula:

Image of equation

We will then use a thin Windows PowerShell wrapper around Math.NET Numerics called Math.NET PowerShell to calculate it in Windows PowerShell. The Windows PowerShell module offers a familiar way to initialize matrices (such as m "1 0;0 1" to initialize the identity matrix of order 2) and an easy approach to using the adequate Math.NET Numerics matrix type.

By default, Math.NET PowerShell uses the most memory conservative matrix type (sparse matrix with single precision). But the precision of this type is too low for our needs. Therefore, we will select the double precision type. This is achieved by using the following command:

Set-MathNetMatrixType Double

When this is done, we express the formula using the previous matrix notation as follows:

function halfTan($t){$t / (((($t |^ 2) + 1) |^ .5) + 1)}

function triangleArea($t){2 * ($t |^ 3) / (-($t |^ 2) + 1)}

 

$t = 1

$t = halfTan $t;

$p = m "4 -4;0 0"

$area = m "1 0;0 2"

$area[1,0]=((2 |^ .5) - 1) |^ 2

$p=$p*$area

0..25 | %{

"{0} t: {1}  a: {2}  ~pi:{3}" -f $_,$t,$area[1,0],$p[0,0];

$t = halfTan $t;

$area[1,0] = triangleArea $t

$p=$p*$area

}

Running this script yields the same approximation for π.

~ Firaz

Thank you for writing a most interesting article, Firaz.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Display the Value of Pi by Using PowerShell

$
0
0

Summary: Use Windows PowerShell to easily display the value of pi.

Hey, Scripting Guy! Question How can I use Windows PowerShell to obtain the value for pi?

Hey, Scripting Guy! Answer Use the Pi static property from the System.Math class:

[math]::pi


Use PowerShell to Archive a Folder and Copy to Server

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create a .zip archive folder and copy it to a server.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a folder that contains scripts. I update these scripts from time-to-time. I like to store the scripts on a central shared server. To save bandwidth, I would like to zip the script folder, and then copy it to the server. Is this possible?

—BB

Hey, Scripting Guy! Answer Hello BB,

Microsoft Scripting Guy, Ed Wilson, is here. This morning I am sipping a cup of English Breakfast tea with a bit of lemon pith, blueberry leaf, strawberry leaf, and a cinnamon stick in it. The combination is sweet with a hint of citrus. The cinnamon stick provides a bit of spice to the flavor. It goes well with a whole grain English muffin and locally sourced butter.

One of the cool things to use with .zip archive files is the Desired State Configuration (DSC) archive resource. To illustrate this, I will use some of the code I wrote earlier in the week to create a .zip archive of a script folder. I will then use Windows PowerShell to copy the archive to a server, and then use DSC to copy the archive and extract the files to an additional server.

Use Windows PowerShell to create a .zip archive

The first thing I want to do is to create a .zip archive folder of a collection of scripts from my workstation. I will zip the files and copy them to a share on a server. In my script, the first thing I do is create a bunch of variables. I use these variables to hold the path to my script folder, the folder for the .zip archive, the name of the script archive file, and the destination folder on the server. Here are the variables:

$source = "C:\scripts"

$archive = "C:\Archive"

$Name = "Script.zip"

$destination = "\\dc1\share\scripts"

Next, I use the Join-Path cmdlet to create the complete path to the archive file that I will create. Here is the command:

$ArchiveFile = Join-Path -Path $archive -ChildPath $Name

Now I create the folder to hold the .zip archive. If the folder exists, an error message will appear, but I specify that I do not want to see any errors by using EA 0. If the folder does not exist, the command returns a DirectoryInfo object, but I do not want to see that either, so I pipe the output to the Out-Null cmdlet. Here is the command:

MD $archive -EA 0 | Out-Null

It is also possible that the Script.zip file might already exist (from a prior use of the script). So if a previous copy exists, I want to delete the file. Here is the command to do that:

If(Test-path $ArchiveFile) {Remove-item $ArchiveFile}

Now I add the assembly that contains the Zipfile .NET Framework class and call the CreateFromDirectory method so that I create my .zip file. Here is the code:

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::CreateFromDirectory($Source, $ArchiveFile) 

The last thing I do is use the Copy-Item cmdlet to copy my newly created Script.Zip file to a share on my server:

Copy-Item -Path $ArchiveFile -Destination $destination -Force 

As shown here, my file now appears on the server:

Image of folder

Here is the complete script:

$source = "C:\scripts"

$archive = "C:\Archive"

$Name = "Script.zip"

$destination = "\\dc1\share\scripts"

$ArchiveFile = Join-Path -Path $archive -ChildPath $Name

MD $archive -EA 0 | Out-Null

If(Test-path $ArchiveFile) {Remove-item $ArchiveFile}

Add-Type -assembly "system.io.compression.filesystem"

[io.compression.zipfile]::CreateFromDirectory($Source, $ArchiveFile)

Copy-Item -Path $ArchiveFile -Destination $destination -Force

Use DSC to copy and extract the file from the server

Now I want to use Windows PowerShell DSC to copy the file from the shared server to a destination server. I also want to extract the .zip file when it arrives at its destination. To do this, I will use a couple of DSC resources that are native to Windows PowerShell 4.0. (This means that I do not need to download or install anything to use this technique.)

The first thing I do is add a #Requires command that states I need Windows PowerShell 4.0. This will ensure that I have at least Windows PowerShell 4.0 when I attempt to run the script. Next, I use the Configuration keyword and specify a name for the configuration. I call it ScriptFolderUnzip, but can use any name that makes sense. I specify the target node of the configuration. I am only targeting a single server called SGW (Scripting Guy Wilson?), and I have it hard-coded in my script. This code is shown here:

#Requires -version 4.0

Configuration ScriptFolderUnzip

{

     node SGW

I specify the DSC resource that I want to use. For the first one, I use the File resource. I again specify a name (here I call it ScriptFiles). There are several parameters that I can specify with the File resource. I am using SourcePath and DestinationPath. These both make sense because I use them to specify the path to the source files and the destination RELATIVE TO THE TARGET NODE path.

This is important to remember. The Source is where I will find the source files, and it is relative to the computer that I use to run the configuration. I am running it from my workstation, so where does my workstation file the files?

Well, it so happens that I created a shared folder on a server, so I can use a UNC path to find the source files. This is a very good practice, and it will help avoid a lot of confusing errors. It doesn't matter from where I run the configuration script—it will always file the source.

The destination is a path relative to the target node. For this, I use a folder named C:\Archive. This is a local folder on the SGW server. It does not have to exist prior to running the configuration.

I then specify Ensure = Present. This means that I want to make sure that a folder named C:\Archive exists, and that it will contain everything that is in the \\DC1\Share\Scripts folder. I also specify that it is of the Type of Directory, and that I want the command to recurse so that it will also create subfolders. Here is the command:

File ScriptFiles

      {

        SourcePath = "\\dc1\Share\Scripts"

        DestinationPath = "C:\Archive"

        Ensure = "present"

        Type = "Directory"

        Recurse = $true

      }

Next I use the Archive DSC resource, and I give command the name of ZippedModule. This command depends on the ScriptFiles command that uses the File resource. The path to the .zip file is C:\Archive\Script.zip (This is the folder and its content that was created by the File resource in the previous command.) I specify the destination of C:\Scripts, and I ensure that it will be present. This is the complete command:

Archive ZippedModule

      {

        DependsOn = "[File]ScriptFiles"

        Path = "C:\Archive\Script.zip"

        Destination = "C:\Scripts"

        Ensure = "Present"

      }

I call the configuration and specify an output folder for the MOF file that gets created by the command. I then call the Start-DSCConfiguration cmdlet, provide the path to the MOF file, and a job name. Here is the complete configuration script:

#Requires -version 4.0

Configuration ScriptFolderUnzip

{

     node SGW

    { 

     Archive ZippedModule

      {

        DependsOn = "[File]ScriptFiles"

        Path = "C:\Archive\Script.zip"

        Destination = "C:\Scripts"

        Ensure = "Present"

      }

    }

}

ScriptFolderUnZip -output C:\SGWConfig

Start-DscConfiguration -Path C:\SGWConfig -JobName SGWConfig -Verbose

I now go to the SGW server and look for the Scripts folder. As shown here, the script worked:

Image of folder

BB, that is all there is to using Windows PowerShell to create a .zip archive and copy that archive to a shared server.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Easily Find PowerShell DSC Resources

$
0
0

Summary: Use Windows PowerShell to easily find DSC resources.

Hey, Scripting Guy! Question How can I find what Desired State Configuration (DSC) resources are installed on my local system?

Hey, Scripting Guy! Answer Use the Get-DSCResource cmdlet.

Updating Virtual Machines

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about the problem of updating virtual machines.

Microsoft Scripting Guy, Ed Wilson, is here. This afternoon I am sipping a nice cup of red berry tea. I also have a bowl of grapes and a bit of brie. The berry tea, grapes, and brie are a nice combination, and light enough that it makes a nice afternoon snack.

One of the great things I love about Windows 8.1 is that it has real Hyper-V built-in to it, and it has Windows PowerShell cmdlet support for managing those virtual machines. The performance is really good, and it means that I can create a virtual machine on my laptop that replicates virtual machines in production. It makes a great test environment.

My test network is completely isolated and I use the internal switch so the virtual machines can talk to each other. This is perfect for most occasions. The problem comes when I want to update those virtual machines.

Here is an overview of the scenario...

I need to first change from the internal switch type to a network adapter that uses the Ethernet connection. Luckily, I can do this while the virtual machine runs. I open Hyper-V Manager, right-click the name of the virtual machine, and choose Settings from the action menu. I then look for Network adapter under the Hardware section. I change the network adapter (virtual switch) to use the Ethernet network adapter from my host machine. This is shown here:

Image of menu

Now I need to go into the virtual machine and modify the network adapter settings. This means that I right-click the network adapter icon on the tool bar, I choose Open Network and Sharing Center, select Change adapter settings, find my network adapter in Network Connections, right-click the adapter, choose Properties, scroll down until I find Internet Protocol Version 4 (TCP/IPv4), and again select Properties.

Now I change from a static IP address to a dynamic-assigned IP address and DNS. This is shown here:

Image of menu

Then I click OK, click Close, X, X…wait for things to freeze a couple times, open Windows PowerShell, type IPConfig and look to see if I have a new IP address. If I do, great! If not, I need to investigate ipconfig/renew.

If that doesn’t work, I need to disable the network adapter, re-enable it, and type ipconfig/renew again. If that doesn’t work, I reboot the virtual machine. Usually that will work. Today, it looks like everything is going well, and that it works. I open Internet Explorer to verify that I have Internet connectivity. This also works.

So I open Control Panel, System and Security, Windows Update, and Check for Updates, and again wait a while...

As shown here, there are a few updates that I need to install:

Image of menu

And now I wait for a while again. Hmmm…

While I am waiting, I think I will go make a cup of tea. Back in a while...

Well, that all took a while, and now I need to reboot the virtual machine. Then I have to reverse the process: change back to the virtual switch, go back into the network adapter, and configure a static IP address.

So there is a description of the problem I face. When I have multiple virtual machines that I need to update, it takes a while. So, this becomes a great area for automation—and that is just what Sean will do tomorrow.

Join me tomorrow when I have a guest article by Microsoft PowerShell MVP and Honorary Scripting Guy, Sean Kearney. He will talk about performing an offline update.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find Network Adapters

$
0
0

Summary: Use Windows PowerShell to find network adapters associated with running virtual machines.

Hey, Scripting Guy! Question How can I use Windows PowerShell to see the network adapters that are associated with all running
           virtual machines on my Windows 8.1 laptop that runs Hyper-V?

Hey, Scripting Guy! Answer Use the Get-VM cmdlet to look for running virtual machines. Then pipe the results to the 
           Get-VMNetworkAdapter cmdlet, for example:

(Get-VM).where({$_.state -eq 'running'}) | Get-VMNetworkAdapter

Note  This command must be run with Admin rights. It also uses the Where method syntax
introduced in Windows PowerShell 4.0.

Update Offline Virtual Machine with PowerShell and WSUS Offline Update: Part 1

$
0
0

Summary: Honorary Scripting Guy, Sean Kearney introduces a cool tool for updating virtual machines.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have some virtual machines that are normally offline. They need to be updated on a regular basis, but these machines have no access to the Windows Server Update Services (WSUS) server. Is there an easy answer to this problem?

—WT

Hey, Scripting Guy! Answer Hello WT,

Honorary Scripting Guy, Sean Kearney, is here to show a little magic with Windows PowerShell and the Windows update system.

Updating an offline virtual machine really isn’t that difficult. Just power it up, wait for the updates to download from Microsoft or your central updating system, and…

Oh, wait a minute. That doesn’t cover all scenarios does it? What about virtual machines that never get attached to the production LAN? Or virtual machines that operate in a secure network structure, which is isolated from the Internet and the production update system for security reasons?

Even if you have access to a centralized update system (such as WSUS), you’ll still have to force a download of the updates.

Then what if you had the option to inject the updates directly into the virtual machine...maybe a process that didn’t even need network access? Would that not be an interesting option?

That option is yours to have! There is a free tool that you can download from the Internet called WSUS Offline Update. It’s a great tool that runs off donations from the community. It packages the automatic updates into a folder structure that you can burn to DVD or CD, store on portable USB media, or any other distribution solution your mind can imagine.

By leveraging this solution and a little Windows PowerShell, we can provide an easy-to-automate solution to inject those updates into offline VHD files.

First we need to download and configure WSUS Offline Update. This is quite simple to do. Go to the WSUS Offline Update website, click the Download button, and choose the link in the right pane. You will be downloading a single ZIP file that contains everything you’ll need to implement this easy-to-use solution.

Image of site

After it is downloaded, unblock the ZIP archive. I have found that if you don’t unblock ZIP archives it can actually affect the content, especially the MSI files within it.

Image of menu

Extract that ZIP archive to your folder of choice by right-clicking the file and selecting Extract All.

Image of menu

For our purposes today, I am going to place it at the root of drive C. It will automatically create a folder called WSUSOffline.  Click the Extract button to complete the process.

Image of menu

Now that you have extracted WSUS Offline Update, it’s time to configure.  This is actually very easy to do or to change afterwards. Navigate to the C:\Wsusoffline folder and run the UpdateGenerator.exe application.

We are going to target the following collections of updates:

  • Windows 8.1 and Windows Server 2012 R2
  • C++ Runtime Libraries and .NET Framework
  • Microsoft Security Essentials
  • Windows Defender definitions (for updating the antivirus while offline)

We could also expand this collection into updates for Microsoft Office 2013, 2010, and 2007, but we’ll focus on a simpler configuration at this time.

We are also going to create a single folder that will act as the medium. The author targets a USB key, but in actuality, the folder can exist anywhere. It provides the updates in addition to all the executables needed to inject the updates.

In the following image, note the configuration changes highlighted in red:

Image of menu

Click the Start button to continue. You may be prompted to update your Trusted Root Certificates. Please do so if prompted.

Image of message

At this point, the system will begin downloading the updates into the WSUSOffline folder structure. Grab a nice mint tea and sit down. This will take a while...

Image of code

Done with your tea? Maybe take in a Doctor Who episode while you were waiting? (I did!) When it’s done, we can get to the fun stuff!

WT, sorry but that is all for today. Please come back tomorrow for the rest of the story.

We invite you to follow us on Twitter and Facebook. If you have any questions, send email to scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow.

Sean Kearney, Microsoft PowerShell MVP and Honorary Scripting Guy

Viewing all 2129 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>