Setting VLAN from CSV File in PowerCLI Script - powershell

I am trying to compile a PowerCLI script to help automate the creation of VMs from a CSV file's data. Currently the script I am running looks like this:
# Specify vCenter Server, vCenter Server username and vCenter Server user password
write-host “Please specify vCenter Server and enter credentials” -foreground green
$vc = read-Host "Connect to which vCenter Server?"
write-host “Connecting to vCenter Server $vc” -foreground green
$CSVPath = "$ScriptRoot\PROD_VMRequestTEST.xlsx.csv"
Connect-VIServer -Server $vc
$CSVFile = Import-Csv -Path $CSVPath
Import-Csv -Path $CSVPath
# Specify vCenter Server Virtual Machine & Templates folder
$Folder = “Discovered virtual machine”
#
# Specify the vSphere Cluster
$Cluster = 'vSphere 5.5 RND'
$esx = Get-Cluster $Cluster | Get-VMHost -State connected
Import-Csv -Path $CSVPath | %{
Write-Host “Creation of VM $_.Name initiated” -ForegroundColor green
New-VM -Name $_.Name -VMHost ($esx | Get-Random) -Location $Folder
Write-Host “Power On of the VM $_.name initiated” -ForegroundColor green
Start-VM -VM $_.Name -confirm:$false -RunAsync
}
I have encountered a few examples online dealing with setting the VLAN via PowerCLI but none of them seem to relate directly to my example of using the CSV file to determine the VLAN.
One example I tried using with my script was:
$VMhost = Get-vmhost $_.VMHost
$PortGroup = Get-VirtualPortgroup -name $_.VLAN -VMhost $VMhost
However, I get errors relating to the -Name argument in that line.

On the script context, I believe the error is causing because one of the columns value seems empty(in your case its Name). I can see that you are getting all the values in a foreach loop. I would recommend you to create a sample csv, insert only 2 set of data and see if it works. This way atleast you can narrow down the issue.
Hope this helps...!!!

Related

Get-ChildItem on Multiple Computers, Performance Issues

I'm wanting to improve on my script to be able to accomplish the following:
Scan servers based on get-adcomputer on specific OUs.
Scan each server based on whatever drive letter it has.
Scan each server for log4j.
Export all results to a CSV that identifies the folder path, name of file, and the server that the file was found on.
I have been using the following code to start with:
$Servers = Get-ADComputer -Filter * -SearchBase "OU=..." | Select -ExpandProperty Name
foreach ($server in $Servers){
Invoke-Command -ComputerName $Server -ScriptBlock {
$Drives = (Get-PSDrive -PSProvider FileSystem).Root
foreach ($drive in $Drives){
Get-ChildItem -Path $drive -Force -Filter *log4j* -ErrorAction SilentlyContinue | '
foreach{
$Item = $_
$Type = $_.Extension
$Path = $_.FullName
$Folder = $_.PSIsContainer
$Age = $_.CreationTime
$Path | Select-Object `
#{n="Name";e={$Item}}, `
#{n="Created";e={$Age}},`
#{n="FilePath";e={$Path}},`
#{n="Extension";e={if($Folder){"Folder"}else{$Type}}}`
} | Export-Csv C:\Results.csv -NoType
}
}
I am having the following issues and would like to address them to learn.
How would I be able to get the CSV to appear the way I want, but have it collect the information and store it on my machine instead of having it on each local server?
I have noticed extreme performance issues on the remote hosts when running this. WinRM takes 100% of the processor while it is running. I have tried -Include first, then -Filter, but to no avail. How can this be improved so that at worst, it's solely my workstation that's eating the performance hit?
What exactly do the ` marks do?
I agree with #SantiagoSquarzon - that's going to be a performance hit.
Consider using writing a function to run Get-ChildItem recursively with the -MaxDepth parameter, including a Start-Sleep command to pause occasionally. Also, you may want to note this link
You'd also want to Export-CSV to a shared network drive to collect all the machines' results.
The backticks indicate a continuation of the line, like \ in bash.
Finally, consider using a Scheduled Task or start a powershell sub-process with a lowered process priority, maybe that will help?

Trying to export all permissions in a share using NTFSSecurity powershell module

Hi I'm attempting to export file share permissions but as is typical the file path length for a lot of our shares exceeds 260 characters.
From what I can tell the NTFSSecurity module (https://www.powershellgallery.com/packages/NTFSSecurity/4.2.4) should work past 260 character length but I don't think it's working correctly due to dir not supporting past 260 character length.
Any assistance that can get the below working with the module is appreciated.
Get-Module -ListAvailable
Import-module -name NTFSSecurity
set-location -path D:\Shares\
Dir -dir -recurse | Get-ntfsaccess |export-csv c:\temp\test.csv
If you wanna get fancy the below is a much better version prompts to enter path instead of altering the script and the policy setting at the end now waits for a Y/N input to set it instead of setting it the second it's done with the other part of the script.
$path = Read-Host "Please enter path"
$policy = get-executionpolicy
Set-executionpolicy bypass
Get-Module -ListAvailable
Import-module -name NTFSSecurity
Get-ChildItem2 -Path $Path -Recurse -Directory| Get-ntfsaccess |export-csv c:\temp\fileshareoutput.csv
$msg = 'has the file stopped growing? [Y/N]'
do {
$response = Read-Host -Prompt $msg
if ($response -eq 'y') {
Set-executionpolicy $policy
write-host 'policy set to'
write-host $policy
}
} until ($response -eq 'n')

Why PowerCLI script creates duplicate records using get-vm?

I am trying to build a script that will extract list of VMs from several vsphere servers. At this point it does what I want, but unfortunately it also creates duplicate values in results .csv file.
Just for note serverlist.txt and vicredentials.xml contains the same unique servers.
Import-Module VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode Multiple -Confirm:$false
if (Test-Path 'E:\vSphereScript\vCenterVMList.csv'){Remove-Item 'E:\vSphereScript\vCenterVMList.csv'}
$serverList = Get-Content -Path "E:\vSphereScript\serverlist.txt"
foreach ($server in $serverList) {
$creds = Get-VICredentialStoreItem -file "vSphereScript\vicredentials.xml" -Host $server
Connect-VIServer -server $creds.host -user $creds.user -password $creds.password
Get-VM | Select-Object Name, Guest, VMhost, ResourcePool | Export-Csv -Path "E:\ProgramData\vCenterVMList.csv" -NoTypeInformation -Append
Disconnect-VIServer $server -Confirm:$false
}
Also does anyone have idea why this is so slow?
If I connect to vm directly from powershell and use Get-VM it's almost instantaneous
I don't see anything fundamentally wrong with your code but a couple things do come to mind:
Why are you setting DefaultVIServerMode to Multiple if you're only connecting to a single vCenter at a time?
When you say duplicates, is it the entire VM inventory from a vCenter or is it only particular VMs?
Are the duplicate VMs from a singular vCenter or multiple vCenters?
Are you using any replication based software? (example: SRM)
With regards to speed, Get-VM is fast. However, connecting and disconnecting from vCenter servers are not particularly quick actions.

GCE Windows startup scripts & naming

Linux admin pulling out what hair I have left trying to figure out startup scripts for Windows on GCE.
The way I've approached it is the following;
Create a "runonce" script by editing the registry on the "master" image.
Said script does the following;
-
Does a reverse DNS lookup of it's own IP to get the hostname DNS thinks it is and then sets the local hostname to that
Joins the domain
Adds a domain user as autologin (I need this for various reasons)
I GCESysprep the machine
Take an image of the machine after sysprep and make a group template from that
My main issue I'm having is that it's not working at all :) The machines come up, run the script and reboot but god knows what state they're in after they come back, I can't login, reset the password/do anything.
I think ideally what I'd like to do is figure out the best way of doing this, do I host the script in GCE Storage and mark it a startup script in the GCE Console opposed to the registry setting? Is there a better way of renaming the machines?
Here's the script if you're interested;
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
$ipAddresses = (get-netadapter | get-netipaddress | ? addressfamily -
eq 'IPv4').ipaddress
# Filter out any 192.168 172. 10. IP addresses
$ipAddress = $ipAddresses -like "123*"
# Retrieve the hostname from the ??? DNS Server
$fqdn = (nslookup $ipAddresses | sls name | select -last
1).toString().split(":")[1].trim()
# We only need the hostname without the domain info so split it up
$fqdn_items = $fqdn.split(".")
$newComputerName = $fqdn_items[0]
Write-Host "New Computer Name: $newComputerName"
# Get a WMI object representing the current computer
$currentComputer = Get-WmiObject Win32_ComputerSystem
Write-Host "Attempting to change computer name to $newComputerName"
# Set the Computer Name to the hostname found via DNS Lookup to DNS
Server
# This can only be performed before joining the domain otherwise you
get return code 1326
$currentComputer.Rename($newComputerName)
#SET CREDENTIALS
$domain = “mydomain”
$password = “password” | ConvertTo-SecureString -asPlainText -Force
$username = "$domain\joinuser”
$credential = New-Object
System.Management.Automation.PSCredential($username,$password)
# RENAME THE COMPUTER
Rename-Computer -ComputerName (hostname) -NewName $newComputerName -
LocalCredential $credentiallocal
sleep 100
# JOIN THE DOMAIN
Add-Computer -DomainName $domain -Credential $credential -force
# CONFIGURE AUTOLOGIN
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Winlogon' -Name AutoAdminLogon -Value 1
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Winlogon' -Name DefaultUserName -Value
“mydomain\dr-worker"
New-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Winlogon' -Name DefaultPassword -Value mypassword
restart

Why am i receiving RPC server is unavailable error when looping?

I have a Powershell script to find specific servers and their corresponding service accounts. If I modify the script to use a single server and a single service account, the results are what I expect. If I loop thru the servers and accounts, I receive the following error:
#################################################################
# Find Service Account(s) used to start Services on a Server(s) #
#################################################################
$accounts = (Get-Content C:\Users\location\Scripts\Service_Accounts.txt)
Remove-Item -path C:\Users\location\Scripts\ServiceAccountFnd.txt -force -erroraction silentlycontinue
Import-Module ActiveDirectory # Imports the Active Directory PowerShell module #
## Retrieves servers in the domain based on the search criteria ##
$servers=Get-ADComputer -Filter {Name -Like "namehere*"} -property *
## For Each Server, find the services running under the user specified in $account ##
ForEach ($server in $servers) {
Write-Host $server
ForEach ($account in $accounts) {
Write-Host $account
Get-WmiObject Win32_Service -ComputerName $server | Where-Object {$_.StartName -like "*$account*"} | Format-Table -HideTableHeaders -property #{n='ServerName';e={$_.__SERVER}}, StartName, Name -AutoSize | Out-File -FilePath C:\Users\location\Scripts\ServiceAccountFnd.txt -append -Width 150
}
}
Your $server variable does not only contain the hostname, but also all attributes of the AD computer object.
Try to change the ComputerName value to $server.name.
If that doesn't help: Can you confirm, that you used the very same computer in the loop as without the loop, as you described? I'd assume that you try to access another computer, which is not configured as expected.
Besided that, I'd recommend you to use Get-CimInstance rather than Get-WmiObject, as it doesn't use RPC, but WinRM by default. WinRM is more firewall friendly, secure and faster.