I'm trying to create a list of all servers in the domain and note which ones are being backed up. I'm using a Quest plugin for the AD server list and a Veeam plugin for the back up list. The arrays being created, but I'm having trouble understanding how to compare and create the final list.
# Get list of all servers in AD
if ((Get-PSSnapin -Name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin Quest.ActiveRoles.ADManagement
}
$servers = get-qadcomputer -SizeLimit 0 | where {$_.OSName -match "Server"}
$arrAllServers = #()
foreach ($server in $servers) {
$singleserver = New-Object PSObject
$singleserver | Add-Member -Name "Name" -Value $x.name -MemberType NoteProperty
$arrAllServers += $singleserver
}
# Get list of servers being backed up
if ((Get-PSSnapin -Name VeeamPSSnapin -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin VeeamPSSnapin
}
Connect-VBRServer -Server host.foo.org -Port 9392
$allDetails = #()
$jobs = Get-VBRJob | ?{$_.JobType -eq "Backup"}
# Loop through each job adding details to array
foreach ($job in $jobs) {
$Object = Get-VBRJobObject -Job $job
$jobOptions = New-Object PSObject
$jobOptions | Add-Member -MemberType NoteProperty -Name "Name" -value $job.name
$jobOptions | Add-Member -MemberType NoteProperty -Name "Enabled" -value $job.isscheduleenabled
$jobOptions | Add-Member -MemberType NoteProperty -Name "Servers" -Value (#($Object.name) | Out-String).Trim()
$jobOptions | Add-Member -MemberType NoteProperty -Name "Backup Mode" -value $job.backuptargetoptions.algorithm
$repo = (Get-VBRBackupRepository | ?{$_.HostId -eq $job.TargetHostId -and $_.Path -eq $job.TargetDir}).name
$jobOptions | Add-Member -MemberType NoteProperty -Name "Repository" -value $repo
$allBackupDetails += $jobOptions
}
Disconnect-VBRServer
# Now match by server name and produce some output.
foreach ($lserver in $arrAllServers) {
foreach ($bserver in $allDetails) {
if($lserver.name -eq $bserver.servers) {
Write-Host $lserver.name $bserver.name
}
}
}
You create the array $allDetails and read from it, but you write the objects to $allBackupDetails
$bserver.servers is an array so you need to use -contains or -in
$bserver.servers might be "broken" because of your out-string-operation (why use it?)
$arrAllServers is wasted resources when you only want the servername.
Try:
# Load modules
if ((Get-PSSnapin -Name Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin Quest.ActiveRoles.ADManagement
}
if ((Get-PSSnapin -Name VeeamPSSnapin -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin VeeamPSSnapin
}
# Get list of all servers in AD
$servers = get-qadcomputer -SizeLimit 0 | where {$_.OSName -match "Server"} | Select-Object -ExpandProperty Name
# Get backup jobs
Connect-VBRServer -Server host.foo.org -Port 9392
$allBackupDetails = #()
$jobs = Get-VBRJob | ?{$_.JobType -eq "Backup"}
# Loop through each job adding details to array
foreach ($job in $jobs) {
$Object = Get-VBRJobObject -Job $job
$jobOptions = New-Object PSObject
$jobOptions | Add-Member -MemberType NoteProperty -Name "Name" -value $job.name
$jobOptions | Add-Member -MemberType NoteProperty -Name "Enabled" -value $job.isscheduleenabled
$jobOptions | Add-Member -MemberType NoteProperty -Name "Servers" -Value #($Object.name)
$jobOptions | Add-Member -MemberType NoteProperty -Name "Backup Mode" -value $job.backuptargetoptions.algorithm
$repo = (Get-VBRBackupRepository | ?{$_.HostId -eq $job.TargetHostId -and $_.Path -eq $job.TargetDir}).name
$jobOptions | Add-Member -MemberType NoteProperty -Name "Repository" -value $repo
$allBackupDetails += $jobOptions
}
Disconnect-VBRServer
# Now match by server name and produce some output.
foreach ($server in $servers) {
foreach ($backupDetails in $allBackupDetails) {
if($backupDetails.servers -contains $server) {
Write-Host "$server is in $($backupDetails.name)"
}
}
}
Related
I'm new to programming.
I want to create an array of 4 objects with different values for each object, without overwriting the previous one.
This is my code:
$WKey = "hkcu:\Software\Microsoft\Windows\CurrentVersion\Uninstall\"
$keys = get-childitem -path hkcu:\Software\Microsoft\Windows\CurrentVersion\Uninstall\
$IN = #{}
foreach ($key in $keys.pschildname){
$name = Get-ItemPropertyValue -Path $WKey$key -name displayname
if ($name -like '*injaz*'){
$HM = #{}
$HM.Name = Get-ItemPropertyValue -Path $WKey$key -name displayname
$HM.Version = Get-ItemPropertyValue -Path $WKey$key -name displayVersion
$HM.Uninstaller = Get-ItemPropertyValue -Path $WKey$key -name UninstallString
$HM.Keyname = $key
$Objectname = New-Object PSobject -Property $HM
$IN.add($Objectname.Name,$Objectname.Version,$Objectname.Uninstaller,$Objectname.keyname)
$Objectname
$IN
}
}
You need to create a pscustom object and add the properties to it.
$WKey = "hkcu:\Software\Microsoft\Windows\CurrentVersion\Uninstall\"
$keys = get-childitem -path hkcu:\Software\Microsoft\Windows\CurrentVersion\Uninstall\
$IN = [System.Collections.ArrayList]#{}
foreach ($key in $keys.pschildname){
$name = Get-ItemPropertyValue -Path $WKey$key -name displayname
if ($name -like '*injaz*'){
#Create object
$HM = New-Object -TypeName psobject
#Add properties to object
$HM | Add-Member -MemberType NoteProperty -Name "Name" -Value $(Get-ItemPropertyValue -Path $WKey$key -name displayname)
$HM | Add-Member -MemberType NoteProperty -Name "Version" -Value $(Get-ItemPropertyValue -Path $WKey$key -name displayVersion)
#Continue with the other values
#Add object to array
$IN.Add($HM) | Out-Null
}
}
I have an array that I write certificate information into using a credential called $array_otheruser but when I try to Export-Csv, the file becomes empty.
However, it writes fine if my export line is within the $ScriptBlock. However, I want to export it out of scriptblock, is this possible?
The code below writes an empty file:
[string][ValidateNotNullOrEmpty()]$passwd = "password"
$secpasswd = ConvertTo-SecureString -String $passwd -AsPlainText -Force
$mycreds = New-Object Management.Automation.PSCredential ("username", $secpasswd)
$array_otheruser = #()
$CSVFile = "c:\temp\temp9.csv"
$Certs = Get-ChildItem Cert: -Recurse
[ScriptBlock]$ScriptBlock = {
$Certs | where {
$_.PsIsContainer -eq $false
} | ForEach-Object ({
$obj | Add-Member -MemberType NoteProperty -Name "NotAfter" -Value $_.NotAfter
$obj | Add-Member -MemberType NoteProperty -Name "NotBefore" -Value $_.NotBefore
$array_otheruser += $obj
$obj = $null
})
}
$otheruser = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $env:computername -Credential $mycreds | Wait-Job
$otheruser | Receive-Job
$array_otheruser | Export-Csv -Path $CSVFile -NoTypeInformation
The code below writes into the file (where I've put the Export-Csv inside the scriptblock):
[ScriptBlock]$ScriptBlock = {
...
$array_otheruser += $obj
$obj = $null
})
##########This is the key difference, the export line is inside the ScriptBlock
$array_otheruser | Export-Csv -Path "c:\temp\temp9.csv" -NoTypeInformation
########
}
$otheruser = Invoke-Command -ScriptBlock $ScriptBlock -ComputerName $env:computername -Credential $mycreds | Wait-Job
$otheruser | Receive-Job
I would like to know if it is possible to have the Export-Csv file line outside of the scriptblock and have the cert information contents populate as it should using a different credential.
I am experiencing an issue with this code where if item(s) in the array returns less than two strings, the string is display as a list.
For example if I have two clusters. The listbox would give me the option to select let's say Test-Cluster and Dev-Cluster; however, if only Test-Cluster is the only available cluster, the listbox would display each letter of the string as a different option in the list box. I can't seem to figure out why. See picture:
#event: when Environment is selected
$wpFBoxEnvironment.Add_DropDownClosed({
Disconnect-VIServer * -Confirm:$false
#empty VCenters inside form
$wpFBoxSrcVCenter.Items.Clear()
$wpFListTgtVCenters.Items.Clear()
#empty Source VMs inside form
$wpFListSrcVMs.Items.Clear()
#validate VI servers connetion and connect if session doesn't exist
$VServers = $vdiEnvironments |
Where-Object Env -like $wpFBoxEnvironment.Text
#notify use to wait for vCenter server login
Write-Host "Logging in to all $($wpFBoxEnvironment.Text) servers. Please wait..."
foreach ($VServer in $VServers) {
$sessionID = ($global:DefaultVIServers | Where-Object -FilterScript {$_.Name -like $VServer.Name}).sessionId
if ($sessionID) {
Connect-VIServer -Server $VServer.Name -Session $sessionID
} elseif ($credential) {
Connect-VIServer -Server $VServer.Name -Credential $credential
} else {
throw 'Connection Error'
}
}
$clusters = Get-Cluster | Select-Object Name, Uid
$clusters | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.Uid.Split('#')[1].Split(':')[0]
}
$datastores = Get-Datastore | Select-Object -Property Name, DatastoreBrowserPath, FreeSpaceMB, CapacityMB
$datastores | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.DatastoreBrowserPath.Split('\')[1].replace('#443','')
$_.FreeSpaceMB = [int]$_.FreeSpaceMB
$_.CapacityMB = [int]$_.CapacityMB
}
$portgroups = Get-VDPortgroup | Select-Object VlanConfiguration, Name, NumPorts, Uid | ? VlanConfiguration -notlike "*0-4094*"
$portgroups | ForEach-Object {
$_ | Add-Member -MemberType NoteProperty -Name VCName -Value $_.Uid.Split('#')[1].Split(':')[0]
$_.NumPorts = [int]$_.NumPorts
}
$vCenters = #()
foreach ($vCenter in $VDIEnvironments) {
#Find single clusters and padd array
if (($clusters | ? VCName -like $vCenter.Name).Count -eq 1) {
$clusters += ("-----")
}
$vCenter |
Add-Member -MemberType NoteProperty -Name TargetCluster -Value (
$clusters | ? VCName -like $vCenter.Name
)[0].Name -Force
$vCenter |
Add-Member -MemberType NoteProperty -Name Clusters -Value $(
$clusters | ? VCName -like $vCenter.Name
).Name -Force
$vCenter |
Add-Member -MemberType NoteProperty -Name TargetDatastore -Value $(
$datastores | ? VCName -like $vCenter.Name | Sort-Object -Descending FreeSpaceMB
)[0].Name -Force
$vCenter |
Add-Member -MemberType NoteProperty -Name Datastores -Value $(
$datastores | ? VCName -like $vCenter.Name
).Name -Force
$vCenter |
Add-Member -MemberType NoteProperty -Name TargetPortgroup -Value (
$portgroups | ? VCName -like $vCenter.Name | Sort-Object -Descending NumPorts
)[0].Name -Force
$vCenter |
Add-Member -MemberType NoteProperty -Name Portgroups -Value $(
$portgroups | ? VCName -like $vCenter.Name
).Name -Force
$vCenters += $vCenter
}
#fill VCenters inside form from selected Environment
$selectedVCenters = $vCenters |
Where-Object Env -like $wpFBoxEnvironment.Text |
Where-Object Datastores -ne $Null
$selectedVCenters | ForEach-Object {
$wpFBoxSrcVCenter.Items.Add($_.Name)
$wpFListTgtVCenters.Items.Add($_)
$wpFListTgtVCenters.SelectedItems.Add($_)
}
})
<GridViewColumn Header="Target Cluster"
Width="160" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding 'Clusters'}"
SelectedItem="{Binding Path='TargetCluster', Mode=TwoWay}"
Width="145"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
I think it's because you are iterating over either an array, or in the case of a single item, a string. Try predefining your array then add (+=) to it. That way in the case of a single string it will still be an array:
Edit:
Looking at the data, it looks like you may have to explicitly convert the single string to an array by wrapping $_ in #(..) to get: #($_)
This will either convert the string into a single value array, or keep the existing array. More info: about_arrays
...
#fill VCenters inside form from selected Environment
$selectedVCenters = #()
$selectedVCenters += $vCenters |
Where-Object Env -like $wpFBoxEnvironment.Text |
Where-Object Datastores -ne $Null
$selectedVCenters | ForEach-object {
$wpFBoxSrcVCenter.Items.Add($_.Name)
$wpFListTgtVCenters.Items.Add(#($_))
$wpFListTgtVCenters.SelectedItems.Add($_)
}
I want to get data from 2 commands and combine them into 1 object.
My goal is to get usage and cost of the Partner center. To do this I got the usage and cost with the command Get-PartnerCustomerSubscriptionUsage of the Partner center module. But when i Retrieve information of my customer/subscription I got the ugly ResourceID inside my report. And this is not presentable. This is why I need to get the real ResourceName, not the Resource name that is provided with the Get-PartnerCustomerSubscriptionUsage command.
After some digging in the documentation I got an idea to retrieve the ResourceUri that has the entire uri like /subscription/xxxxx/Resourcegroup/xxxx/ms.vm/The name that i want in my report. The command that has this value is : Get-PartnerCustomerSubscriptionUtilization. So I guessed that I just ditch the Get-PartnerCustomerSubscriptionUsage and use the PartnerCustomerSubscriptionUtilization instead , but this one does not have the totalcost per azure Resource.
Oké hang on with me the problem is getting there.
So now I created a Powershell script that will run the both commands , and combine them inside an Powershell object that will be exported to a csv. I can get one command running , providing the info from that command object into my custom object that is created and export it to csv. The problem is starting when I want to combine the both.
$Customers= Get-PartnerCustomer
for ($i=0 ; $i -lt $Customers.length; $i ++){
$subscription = Get-PartnerCustomerSubscription -CustomerId $Customers[$i].CustomerId
for ($j=0 ; $j -lt $subscription.length; $j ++){
if ( $subscription[$j].UnitType -eq "Usage-based" )
{
#Create title in csv
$customerId = $Customers[$i].CustomerId
$customerName= $Customers[$i].Name
$subscriptionId = $subscription[$j].SubscriptionId
$subscriptionName = $subscription[$j].OfferName
$usage = Get-PartnerCustomerSubscriptionUsage -CustomerId $customerId -SubscriptionId $subscriptionId
#new object for the export excel
$ExportExcel = New-Object -TypeName PSObject
$array = New-Object -TypeName PSObject
$End= (get-date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss-08:00")
$Start = (Get-Date).AddDays(-1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss-08:00")
$util = Get-PartnerCustomerSubscriptionUtilization -CustomerId $customerId -SubscriptionId $subscriptionId -StartDate $Start -EndDate $End -ShowDetails
for ($y=0 ; $y -lt $util.length; $y ++)
{
$array = [PSCustomObject][ordered]#{
"ResourceID"=$util[$y].Id
"ResourceName"=$util[$y].ResourceUri.OriginalString
}
}
for ($z=0 ; $z -lt $usage.length; $z ++)
{
$LastModifiedDate = $usage[$z].LastModifiedDate.DateTime.ToString("yyyy-MM-dd")
if ( $LastModifiedDate -ge $Lastdate )
{
if ($usage[$z].ResourceId -eq $array[$z].ResourceID){
#Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "Category" -Value $array[$z].ResourceName -Force
**echo $array[$z].ResourceName**
}
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "Category" -Value $usage[$z].Category -Force
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "QuantityUsed" -Value $usage[$z].QuantityUsed -Force
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "ResourceId" -Value $usage[$z].ResourceId -Force
}
}
$ExportExcel | Export-Csv –append -Path "C:\$customername.csv" -NoTypeInformation
}
}
}
As you can see I've read everything from one command inside an object and then loop over the other one. Once the resourceID is equal over the both commands, I need to add it to the Object. (for testing I just test this with an echo)
The echo with the ***** doesn't print anything. So I can't get any Resourcename inside my csv. Does anyone have a clue what I am doing wrong. Where the combination of the 2 objects fail ?
Just for grins, I've made a few edits. Can you let me know if this improves the situation?
$Customers= Get-PartnerCustomer
for ($i=0 ; $i -lt $Customers.length; $i ++){
$subscription = Get-PartnerCustomerSubscription -CustomerId $Customers[$i].CustomerId
for ($j=0 ; $j -lt $subscription.length; $j ++){
if ( $subscription[$j].UnitType -eq "Usage-based" )
{
#Create title in csv
$customerId = $Customers[$i].CustomerId
$customerName= $Customers[$i].Name
$subscriptionId = $subscription[$j].SubscriptionId
$subscriptionName = $subscription[$j].OfferName
$usage = Get-PartnerCustomerSubscriptionUsage -CustomerId $customerId -SubscriptionId $subscriptionId
#new object for the export excel
$ExportExcel = New-Object -TypeName PSObject
$array = #()
$End= (get-date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss-08:00")
$Start = (Get-Date).AddDays(-1).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss-08:00")
$util = Get-PartnerCustomerSubscriptionUtilization -CustomerId $customerId -SubscriptionId $subscriptionId -StartDate $Start -EndDate $End -ShowDetails
for ($y=0 ; $y -lt $util.length; $y ++)
{
$array += [PSCustomObject][ordered]#{
"ResourceID"=$util[$y].Id
"ResourceName"=$util[$y].ResourceUri.OriginalString
}
}
for ($z=0 ; $z -lt $usage.length; $z ++)
{
$ExportExcel = New-Object -TypeName PSObject
$LastModifiedDate = $usage[$z].LastModifiedDate.DateTime.ToString("yyyy-MM-dd")
if ( $LastModifiedDate -ge $Lastdate )
{
if ($usage[$z].ResourceId -eq $array[$z].ResourceID){
#Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "Category" -Value $array[$z].ResourceName -Force
**echo $array[$z].ResourceName**
}
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "Category" -Value $usage[$z].Category -Force
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "QuantityUsed" -Value $usage[$z].QuantityUsed -Force
Add-Member -InputObject $ExportExcel -MemberType NoteProperty -Name "ResourceId" -Value $usage[$z].ResourceId -Force
$ExportExcel | Export-Csv –append -Path "C:\$customername.csv" -NoTypeInformation
}
}
}
}
}
I edited the line below to retain all values for each iteration of loop $y.
$array += [PSCustomObject][ordered]#{
"ResourceID"=$util[$y].Id
"ResourceName"=$util[$y].ResourceUri.OriginalString
}
I added the line below so that a new $ExportExcel object could be created to accept your new property additions during loop $z.
$ExportExcel = New-Object -TypeName PSObject
I moved the CSV export line to inside of the $z loop so that each iteration of setting properties for $ExportExcel could be captured.
Can someone help me out with getting the disk info? I have 3 disks but I'm unable to get their information using add member.
I get an error:
"Add-Member : Cannot add a member with the name "Disks" because a member with that name already exists. If you want to overwrite the member anyway, use the Force parameter to overwrite it."
This is my code:
function Get-Inven {
param([string[]]$computername)
#Import-Module ActiveDirectory
foreach ($computer in $computername) {
$disks = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computer -Filter 'DriveType=3'
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
#$comp = Get-ADComputer -Filter { cn=$computer }
$info = #{
'ComputerName'=$computer;
'OSVersion'=$os.caption;
'DnsHostName'=$comp.dnshostname
}
$obj = New-Object -TypeName PSObject -Property $info
foreach ($disk in $disks) {
$info = #{
'DriveLetter'=$disk.deviceID;
'FreeSpace'=($disk.freespace / 1MB -as [int])
}
$diskobj = New-Object -TypeName PSObject -Property $Info
$obj | Add-Member -MemberType NoteProperty -Name Disks -Value $diskobj
}
}
}
You can still set the Name property if you add the -Force parameter. You should also add the -PassThru switch parameter to emit the object back to the pipeline:
$obj | Add-Member -MemberType NoteProperty -Name Disks -Value $diskobj -Force -PassThru
UPDATE:
In my opinion you can simplify the function (no add-member calls):
foreach ($computer in $computername) {
$disks = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computer -Filter 'DriveType=3'
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
#$comp = Get-ADComputer -Filter { cn=$computer }
$info = #{
ComputerName=$computer
OSVersion=$os.caption
DnsHostName=$comp.dnshostname
FreeSpaceMB= ($disks | foreach { "{0},{1:N0}" -f $_.Caption,($_.freespace/1MB) }) -join ';'
}
New-Object -TypeName PSObject -Property $info
}
Since there are multiple disks, you need to create the disk property as an array, then add each disk to the array. Also, remember to output $obj at the end of the $computername foreach.
function Get-Inven {
param([string[]]$computername)
$computername = 'localhost'
foreach ($computer in $computername) {
$disks = Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computer -Filter 'DriveType=3'
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
#$comp = Get-ADComputer -Filter { cn=$computer }
$info = #{
'ComputerName'=$computer;
'OSVersion'=$os.caption;
'DnsHostName'=$comp.dnshostname
}
$obj = New-Object -TypeName PSObject -Property $info
$obj | Add-Member -MemberType NoteProperty -Name Disks -Value #()
$obj | Add-Member -MemberType ScriptProperty -Name DisksList -Value {
($this.Disks|%{$_.DriveLetter + ',' + $_.FreeSpace}) -join ';'
}
foreach ($disk in $disks) {
$info = #{
'DriveLetter'=$disk.deviceID;
'FreeSpace'=($disk.freespace / 1MB -as [int])
}
$diskobj = New-Object -TypeName PSObject -Property $Info
$obj.Disks += $diskobj
}
$obj
}
}
$result = get-inven localhost
$result| select "OSVersion","DnsHostName","ComputerName","DisksList"|ConvertTo-Csv