Create Shortcut based on an AD HomeDirectory - powershell

I'm Trying to create a script to create shortcuts for students based on their AD HomeDirectory and naming the Link as there AD display name. Homedirectory is a UNC path.
However when i get to the $shortcut.targetpath area it complains about invalid parameter. I think it's not liking the data in the $homedir variable. My code is noobish. But i'm still learning. Any help would be great.
###Read a Sisweb Extract
$data=Get-Content C:\studentfile.txt
###For each row in the file execute all of this
foreach ($line in $data)
{
###Parse the row and retrieve SSID
$columns = $line -split '\t'
$studentid = $columns[3]
###If a SSID is found execute the following code.
if($studentid -match "[0-9]")
{
###Retrieve DisplayName of the SSID.
$displayname=Get-aduser $studentid -property displayname |ft displayname -hidetableheaders |out-string
###Retrieve Home Directory of the SSID
$homedir=Get-aduser $studentid -property homedirectory |ft homedirectory -hidetableheaders |out-string
###Parse the homedirectory data and retrieve the servername.
$pathdata="$homedir" -split '\\'
$server=$pathdata[2]
###Create Shortcut
$WshShell=New-Object -comObject WScript.Shell
$Shortcut=$WshShell.CreateShortcut("C:\temp\$displayname.lnk")
$Shortcut.TargetPath="$homedir"
$Shortcut.Save()
}
}

I am going to build an answer since i see a couple of things that should be addressed. Ultimately I think your issue lies with your assignment of $homedir.
if($studentid -match "[0-9]") This code will check to see if $studentid contains a single numerical digit. Was this on purpose? Currently you would get a hit if an ID was sdfhgkjhg3kjg since that contains one digit. A simple addition would be to change it to if($studentid -match "^[0-9]{6}$") for example. Means that it will match a single line that contained exactly 6 digits.
$displayname=Get-aduser $studentid -property displayname |ft displayname -hidetableheaders |out-string I see this twice. I would update this since the Format-Table doesnt really serve a purpose and you can use Select-Object to accomplish your goal.
Get-aduser $studentid -property displayname | select -first 1 -ExpandProperty displayname
Get-aduser $studentid -property homedirectory | select -first 1 -ExpandProperty homedirectory
OR
Instead of call get-aduser twice you could combine both your variable assignments.
$singleStudent = Get-aduser $studentid -property homedirectory,displayname
$displayname = $singleStudent.DisplayName
$homedir = $singleStudent.HomeDirectory

Related

Powershell AD: filter description -like $variable => contains $variable

My task include to filter all users names in group and subgroup in AD. Continue to filter the computers and show just those, which contains filtered names.The problem is, that description includes also other characters like space or "NEW".
My code:
foreach ($file in Get-ADGroupMember -Identity GroupName -Recursive) {Get-ADComputer -Filter 'Description -like $file.name' -Property Name,Description | Select -Property Name,Description}
It would be great to just add * or change -like to -include :D But...
My begginers question is: How to write the code to see all results, not just the ones which match exactly the $file.name?
Thank you for ur time!
Your initial problem was in the Filter you used. With the correct quoting and using the sub-expression operator $() that fixed it.
However, as promised in my comment, here's what I mean on how you can create a report of group members (both users, computers and if you like also subgroups).
Since all objects returned from the Get-ADGroupMember cmdlet have an .objectClass property, you can use that to determine what next Get-AD* cmdlet you can use.
Here, I'm capturing the collected objects output in the foreach() loop in a variable that you can show on screen, or save as Csv file you can open in Excel for instance.
$groupName = 'GroupName'
$result = foreach($adObject in (Get-ADGroupMember -Identity $groupName -Recursive)) {
# use the proper Get-AD* cmdlet depending on the type of object you have
switch ($adObject.objectClass) {
'user' {
$adObject | Get-ADUser -Properties Description | Select-Object Name, Description, #{Name = 'Type'; Expression = {'User'}}
}
'computer' {
$computer = $adObject | Get-ADComputer -Properties Description
# you want to output only the computers where the Description property holds the computer name
if ($computer.Description -like '*$($computer.Name)*') {
$computer | Select-Object Name, Description, #{Name = 'Type'; Expression = {'Computer'}}
}
}
# perhaps you don't want subgroups in your report, in that case just remove or comment out the next part
'group' {
$adObject | Get-ADGroup -Properties Description | Select-Object Name, Description, #{Name = 'Type'; Expression = {'Group'}}
}
}
}
# show the result on screen
$result | Format-Table -AutoSize
# save the result as Csv file
$outFile = Join-Path -Path 'X:\Somewhere' -ChildPath ('{0}_members.csv' -f $groupName)
$result | Export-Csv -Path $outFile -NoTypeInformation -UseCulture
The -UseCulture switch makes sure the Csv file uses the delimiter character your local Excel expects. Without that, a comma is used
Interesting reads:
about_Operators
Adam the Automator
Learn Powershell | Achieve More
and of course StackOverflow

Passing results to a -like filter in PowerShell

I am trying to create a script to take care of a repetitive task I have. Basically I need to get the person's ID that manages a particular folder.
My first script tells me the various security groups assigned to a specified folder. The second script takes a specified AD group and tells me who manages it. Ideally I want to just run the script, input my folder name and have it tell me who manages the various AD groups assigned. I can then go and do the rest. But I am having an issue with the output of the first script. I have it so it displays in the console correctly, but I cannot figure out how to get those results into the filter in the second script.
Script one:
$FN = Read-Host -Prompt "Please enter Folder name"
$ADG = (Get-Acl $FN).Access |
Select IdentityReference |
Where-Object IdentityReference -like '*SL*'
foreach ($ACL in $ADG) {
$Group.Fullname + ($ACL.IdentityReference.Value.Split('\'))[1] | Out-String
}
Script two:
Get-ADGroup -Filter {Name -like "use output here"} -Properties managedby |
Select managedby
I would be most appreciative of any assistance. ESPECIALLY if I am barking up the wrong PowerShell command! My first foray into using multiple queries in a script.
It's not quite clear to me what the $Group.Fullname + (...)[1] | Out-String is supposed to do, but assuming that you want to run the second command for each identity reference from your first command you could do something like this:
Get-Acl $FN |
Select-Object -Expand Access |
Select-Object -Expand IdentityReference |
Where-Object { $_.Value -like '*SL*' } |
ForEach-Object {
$name = $_.Value.Split('\', 2)[-1]
Get-ADGroup -Filter "Name -like '*${name}*'" -Property ManagedBy
} |
Select-Object -Expand ManagedBy |
Get-ADUser

PowerShell -ExpandProperty and correct date format

I am attempting to use the -ExpandProperty feature in PowerShell to stop the header appearing in the output and format the date without minutes and seconds. This is just to get the created date for an AD Object:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object -ExpandProperty #{Name="Created";Expression={$_.Created.ToString("yyyy-MM-dd")}}
This does not produce a result, only if I exclude the "-ExpandProperty" part will it produce the right date format BUT includes the header "Created" which I don't want.
Any ideas please?
I don't have access to an AD at the moment, but this could be what you are after
Updated
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created | Select-Object Created | ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}
To complement LotPings' helpful answer, which offers effective solutions:
As for why your code didn't work:
While Select-Object's -Property parameter accepts hashtables that define calculated properties (such as in your code), the -ExpandProperty parameter only accepts a property name, as a string.
Therefore, your hashtable is simply stringified, resulting in string literal System.Collections.Hashtable, causing Select-Object to complain, given that there is no property by that name.
The purpose of -ExpandProperty is to output just a property value rather than a custom object with that property.
You therefore do not need a detour via Select-Object, and can just use the value-outputting script block - { $_.Created.ToString("yyyy-MM-dd") } - directly with ForEach-Object instead, as shown at the bottom of LotPings' answer.
However, there is an obscure feature that you forgo by using ForEach-Object: Select-Object allows combining -ExpandProperty with -Property, in which case the properties specified via -Property are added as NoteProperty members to the value of the property specified via -ExpandProperty:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } |
Select-Object -ExpandProperty one -Property two; $val; $val.two
uno
2
Note how the output string value, 'uno' has a copy of the input object's .two property attached to it.
To emulate that with ForEach requires more work:
PS> $val = [pscustomobject] #{ one = 'uno'; two = 2 } | ForEach-Object {
$_.one + '!' | Add-Member -PassThru two $_.two
}; $val; $val.two
uno!
2
In PowerShell there nearly always is more than one solution to a problem-
(Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} ).Created
or
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
Select-Object #{N="Created";E{$_.Created.ToString("yyyy-MM-dd")}} |
Select-Object -Expand Created
Parameter names can be shorted as long as they are uniquely identifiable and there are also shortcuts (uppercase letters) so -EA is -ErrorAction
A calculated property does IMO make no sense here as it is the only output, so this should do also:
Get-ADComputer -Server $Server -Identity BlahBlah -Properties Created |
ForEach-Object {$_.Created.ToString("yyyy-MM-dd")}

Out-File won't display what powershell ISE shows

Ok, so I'm a beginner in Powershell.
I'm at work so I wanted to auto some things. My work with this script is to select those specific users and their password expiration date, format the date to be human readable and then save all that in a txt file to be analized.
My current code is this:
$List = Get-Content D:\Users\c05896\Desktop\VIPS.txt
$Users = #()
foreach ($Item in $List){
$Users += Get-ADUser -Filter * -Properties "msDSUserPasswordExpiryTimeComputed"| where {$_.Name -like "*$Item*"}}
$Users | Sort-Object | Select-Object Name, #{Name="Password expires";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed" )}}
Out-File -filepath D:\Users\c05896\Desktop\VIPLista.txt -InputObject $Users
So, the script above is what I wrote.
The output WITHIN the Powershell ISE is at follows:
Name Password expires
---- ---------------
User 1 10/11/2010 01:39:53 p.m.
User 2 21/10/2018 10:21:43 a.m.
User 3 21/10/2018 08:38:23 a.m.
. .
. .
. .
That's what I want to output in the txt file, but instead I got this format:
DistinguishedName : CN=USER LASTNAME
OU=VIPs,OU=Users
Enabled : False
GivenName : USER LASTNAME
msDS-UserPasswordExpiryTimeComputed : 129192702049912335
Name : USER
ObjectClass : user
ObjectGUID : bb033273-6117-470b-9f07-aee2885a45bc
SamAccountName : B00057
SID : S-1-5-21-808411757-1154953693-317593308-27012
Surname : USER
UserPrincipalName : XXXXX
I erased all names and lastnames just for privacy.
So, the question is what can I do to get the Out-File to display the information as it shows on Powershell ISE?
Thank you very much for your answers
# --> $Users = $Users | ...
$Users = $Users | Sort-Object | Select-Object Name, #{Name="Password expires";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed" )}}
Out-File -filepath D:\Users\c05896\Desktop\VIPLista.txt -InputObject $Users
# or
# combine ISE output with file output in one command using Tee-Object
$Users | Sort-Object |
Select-Object Name, #{Name="Password expires";Expression={[datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed" )}} |
Tee-Object -FilePath D:\Users\c05896\Desktop\VIPLista.txt
Nas has a good answer for you regarding how to meet your objective. I'm going to try to answer the why.
When you used Get-ADUser to retrieve your user objects a number of properties are returned by default. You were aware of that and used Select-Object to select which attributes to return and you even added a new custom attribute.
The Select-Object output is what displayed in the ISE (and would have displayed in a console if you weren't using the ISE as well).
What you did not do is actually modify the objects that were stored in the $Users array so when you sent those objects to Out-File it received all the attributes of the objects.
Both of the options that Nas gives you above modify the objects in $Users while they are in the pipeline so that when they are sent to Out-File only the attributes you wanted to output to the file are remaining. His first example actually replaces the original $Users array with a new $Users array so that if you subsequently examine it, only your specified attributes will remain. In his second example, using Tee-Object, $Users still remains unmodified and if you examined the objects you would see that they still retain DistinguishedName, Enabled, GivenName, etc.

Output data with no column headings using PowerShell

I want to be able to output data from PowerShell without any column headings. I know I can hide the column heading using Format-Table -HideTableHeaders, but that leaves a blank line at the top.
Here is my example:
get-qadgroupmember 'Domain Admins' | Select Name | ft -hide | out-file Admins.txt
How do I eliminate the column heading and the blank line?
I could add another line and do this:
Get-Content Admins.txt | Where {$_ -ne ""} | out-file Admins1.txt
But can I do this on one line?
In your case, when you just select a single property, the easiest way is probably to bypass any formatting altogether:
get-qadgroupmember 'Domain Admins' | foreach { $_.Name }
This will get you a simple string[] without column headings or empty lines. The Format-* cmdlets are mainly for human consumption and thus their output is not designed to be easily machine-readable or -parseable.
For multiple properties I'd probably go with the -f format operator. Something along the lines of
alias | %{ "{0,-10}{1,-10}{2,-60}" -f $_.COmmandType,$_.Name,$_.Definition }
which isn't pretty but gives you easy and complete control over the output formatting. And no empty lines :-)
A better answer is to leave your script as it was. When doing the Select name, follow it by -ExpandProperty Name like so:
Get-ADGroupMember 'Domain Admins' | Select Name -ExpandProperty Name | out-file Admins.txt
If you use "format-table" you can use -hidetableheaders
add the parameter -expandproperty after the select-object, it will return only data without header.
The -expandproperty does not work with more than 1 object. You can use this one :
Select-Object Name | ForEach-Object {$_.Name}
If there is more than one value then :
Select-Object Name, Country | ForEach-Object {$_.Name + " " + $Country}
Joey mentioned that Format-* is for human consumption. If you're writing to a file for machine consumption, maybe you want to use Export-*? Some good ones are
Export-Csv - Comma separated value. Great for when you know what the columns are going to be
Export-Clixml - You can export whole objects and collections. This is great for serialization.
If you want to read back in, you can use Import-Csv and Import-Clixml. I find that I like this better than inventing my own data formats (also it's pretty easy to whip up an Import-Ini if that's your preference).
First we grab the command output, then wrap it and select one of its properties. There is only one and its "Name" which is what we want. So we select the groups property with ".name" then output it.
to text file
(Get-ADGroupMember 'Domain Admins' |Select name).name | out-file Admins1.txt
to csv
(Get-ADGroupMember 'Domain Admins' |Select name).name | export-csv -notypeinformation "Admins1.csv"
$server = ('*')+(Read-Host -prompt "What Server Context?")+'*'
$Report = (Get-adcomputer -SearchBase "OU=serverou,DC=domain,DC=com" -filter {name -like $server} -SearchScope Subtree|select Name |Sort -Unique Name)
$report.Name | Out-File .\output\out.txt -Encoding ascii -Force
$Report
start notepad .\output\out.txt
Put your server SearchBase in above.
If you are not sure what your server OU is try this function below...
#Function Get-OSCComputerOU($Computername)
{
$Filter = "(&(objectCategory=Computer)(Name=$ComputerName))"
$DirectorySearcher = New-Object System.DirectoryServices.DirectorySearcher
$DirectorySearcher.Filter = $Filter
$SearcherPath = $DirectorySearcher.FindOne()
$DistinguishedName = $SearcherPath.GetDirectoryEntry().DistinguishedName
$OUName = ($DistinguishedName.Split(","))[1]
$OUMainName = $OUName.SubString($OUName.IndexOf("=")+1)
# $Obj = New-Object -TypeName PSObject -Property #{"ComputerName" = $ComputerName
# "BelongsToOU" = $OUMainName
# "Full" = $DistinguishedName}
$Obj = New-Object -TypeName PSObject -Property #{"Full" = $DistinguishedName}
$Obj
}
Makes sure to run the Get-OSCComputerOU Servername with a select -expandproperty Full filter.
Then just plug in the response to the Searchbase...
All thanks to http://www.jaapbrasser.com