I"m trying to write a script to delete a VM on a certain date. Currently, I want people to add this to the VM name "VMname_Delete-/1/1/14", I then search for the VM with:
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"}
With that, I'm sure that the correct VM is selected, and I tested it with some VMs to make sure. Now comes the hard part (at least for me), I want to take the date that's part of the VM name, and convert it to a [DateTime] value, and then compare it to the current date. If they match, I want to delete the VM. I was trying something along the lines of:
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach { $_.name -split "-"}
That of course split the dash, and on testing, I had an output similar to:
VM_Delete
1/1/14
Of course, now I don't know how to finish the rest. I was thinking that the script would go something like:
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach {
if ( ($_.name -split "-") -as [datetime] -match (get-date -format "MM/dd/yy") )
{Remove-VM -VM $_ -DeletePermanently}
}
I can think of the logic in my head, but of course, I just can't write it up they way I think that it should go. Any help is appreciated.
You could perhaps do something along these lines
$now = Get-Date
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach {
$dt = [datetime]($_.Name.Split('-')[1])
if($dt -lt $now){
Remove-VM -VM $_ -DeletePermanently
}
}
With the use of the index ([1]), we select the date part of the VM name.
Then we 'cast' the string to a DateTime object.
Note that this cast might cause problems, depending on the culture settings you use.
Worst case, you split the date string on the '/' character, and then generate the DateTime object like this
$now = Get-Date
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach {
$dummy,$day,$month,$year = $_.Name.Split('-')[1].Split('/')
$dt = Get-Date -Day $day -Month $month -Year $year
if($dt -lt $now){
Remove-VM -VM $_ -DeletePermanently
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
You could perhaps do something along these lines
$now = Get-Date
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach {
$dt = [datetime]($_.Name.Split('-')[1])
if($dt -lt $now){
Remove-VM -VM $_ -DeletePermanently
}
}
With the use of the index ([1]), we select the date part of the VM name.
Then we 'cast' the string to a DateTime object.
Note that this cast might cause problems, depending on the culture settings you use.
Worst case, you split the date string on the '/' character, and then generate the DateTime object like this
$now = Get-Date
Get-VM | where {$_.name -cmatch "Delete-\d\/\d\/\d"} | foreach {
$dummy,$day,$month,$year = $_.Name.Split('-')[1].Split('/')
$dt = Get-Date -Day $day -Month $month -Year $year
if($dt -lt $now){
Remove-VM -VM $_ -DeletePermanently
}
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks for your help, what you did makes sense, but I'm having a slight issue. I forgot that with vCenter or maybe it's the host, but there is an issue with forward slash "/" when it's used in a name, vCenter will make it a percent symbol, so I decided to use dashes for the date. But that's not where the problem is.
I've tried this as a test, just to play with splitting the name and making it into datetime
$now = Get-Date
$name = "Delete-09-09-13" | foreach {
$dt=[datetime]($name.split("-",2)[1])
if ($now.Month -eq $dt.Month) {
Write $_
}
}
When I try this I get an error:
You cannot call a method on a null-valued expression
It seems as if $name turns into a $null
My thinking was that I was going to match the datetime with the Month, Day, and year, and as long as those matched, I would delete the VM.
Here is what I tried with your script:
$now = Get-Date
Get-folder Test | Get-VM | where {$_.name -cmatch "Delete-\d\-\d\-\d"} | foreach {
$dt=[datetime]($_.name.Split("-",2)[1])
if ($dt -lt $now) {
Remove-VM
}
}
I get this error:
Cannot convert value "Delete-9-9-13" to type "System.DateTime". Error: "The string was not recognized as a valid DateTime. There is an unknown word starting at index 0."
It works fine when I go right to the command line and I try something like this:
$Name = "Delete-09-09-13"
$dt = [datetime]($name.split("-",2)[1])
That will make $dt into a date, and if I created a variable with Get-Date, I can match up the Month, Day, and Year, but when it's all in a script, it errors.
After some testing, the script below runs fine on the first pass, but if ran a second time, it will throw the error You cannot call a method on a null-valued expression
What doesn't make sense is if I'm assigning a new variable every time, it should work every time, at least it seems as if it should. I stepped through the lines and when the new variable is created with the contents "Delete-09-09-13", it is initially a string, and it shows the value of "Delete-09-09-13", but after that first run, the value shows as a PSCustomobject, it it never shows a string again, even though I thought it should override the variable and create a new one.
$now = Get-Date
$test = "Delete-09-09-13" | % {
$dt=[datetime]($test.split("-",2)[1])
if ($now.Month -eq $dt.month) {
Write-Host $dt.Month, $dt.Day, $dt.Year #this shows up fine the first time, on subsequent runs, I get an error, but it still writes the dates
}
}
Interesting, I tried a small change, and I moved [datetime] in front of the $dt, and it seems to be working. Thanks for your help, but I'm curious why it works this way.
$now = Get-Date
Get-folder Test | Get-VM | where {$_.name -cmatch "Delete-\d\-\d\-\d"} | foreach {
[datetime]$dt=($_.name.Split("-",2)[1])
if ($dt.Month -eq $now.Month) {
Remove-VM -VM $_ -Confirm
}
}
Typed before I truly tested. Although, the script works, I am still getting this error:
Cannot convert value "Delete-09-09-13" to type "System.DateTime". Error: "The string was not recognized as a valid DateTime. There is an unknown word starting at index 0."
Overall, this is the main part of the script, and again, thanks for your help
$now = Get-Date
Get-folder Test | Get-VM | where {$_.name -cmatch "Delete-\d\d\-\d\d\-\d\d"} | foreach {
[datetime]$dt=($_.name.Split("-",2)[1])
if ($dt.Month -eq $now.Month -and $dt.Day -eq $now.Day -and $dt.Year -eq $now.Year) {
Remove-VM -VM $_ -Confirm
}
}
I receive the notification to remove the VM, but I also receive the error message. I guess I could just silientlycontinue, but I'm curious why this happens. I've tried the script on 2 VMs, and it always works, I just don't know why the message comes up. In any event, thanks for leading me on the right path.
Why did you have the ForEach loop (%) in the previous test script ?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
I just left it there since it was going to be multiple VMs anyway, I just didn't take it out for the test.
I made some more changes because we have some VMs that may have a dash already in the name, and since I don't know how many dashes may be in the name, it was easier to use an underscore, and then use a dot(.) for the date separator. Overall, sit seems to work very well. I'm also using a 2 digit date, I want to make 100% sure that I only pull the VMs that need to be deleted, and if the date isn't correct, I'll just have an email send out the name, and those can be deleted manually.
I still have to complete the script, but the hard part is over thanks to you.
$now = Get-Date
Get-folder Test | Get-VM | where {$_.name -cmatch "Delete_\d\d\.\d\d\.\d\d"} | foreach {
[datetime]$dt=($_.name.Split("_",2)[1])
if ($dt.Month -eq $now.Month -and $dt.Day -eq $now.Day -and $dt.Year -eq $now.Year) {
Remove-VM -VM $_ -Confirm
}
else
{Send-MailMessage -SmtpServer '12.8.1.6' -From "<@s.com>" -To "<s@c.com>" -Subject VMs -Body $_.name}
}