list all vendors in azure ad who had logged/never logged in the past 24 hours - azure

I wrote a script to list all vendors in the azure ad to check if they are working or not. the script find the logged in users for the past day and if there is a record it should print, if there is no record and the vendor did not logged in or work it should print no login records. but my script is not working well any one can help?
###########################Here is the code ##################
#get azure ad users
$AzADUsers = get-azureaduser
#start for loop
foreach ($user in $AzADUsers){
#list attributes
$dp = $user.DisplayName
$company = $user.CompanyName
# list of contractors/vendors who didn't log in during the day.
if ($company -eq "Vendor Resource - companyname1" -or $company -eq "Vendor Resource - companyname2" -or $company -eq "Vendor Resource - companyname3") {
#check if they logged in the past 24 hours
$SetDate = (Get-Date).AddDays(-1);
$SetDate = Get-Date($SetDate) -format yyyy-MM-dd
$AllSiginLogs = Get-AzureADAuditSignInLogs -Filter "createdDateTime gt $SetDate"
$LoginRecord = $AllSiginLogs | Sort-Object CreatedDateTime -Descending
if($LoginRecord.Count -gt 0){
$lastLogin = $LoginRecord[0].CreatedDateTime
}
else{
$lastLogin = 'no login record | Sick'
}
Write-Host "Last logon time : " $lastLogin $dp $company
Write-Host " "
}
}

in addition to our discussion:
Currently you loop through the $AzAdUsers and query foreach the SignInLogs. But you do not filter the SignInLogs for the specific user, you query all the time the same information and select the latest entry from that log, but it has no relation to the current user.
You have to filter the SignInLog for the specific user, e.g.:
$AllSiginLogs = Get-AzureADAuditSignInLogs -filter "Id eq '$($user.Id)' and createdDateTime gt $SetDate"
After that you could do:
$attrsht = #{
userId=$User.id
DisplayName=$user.displayname
LastSignIn=$LoginRecord.CreatedDateTime
}
new-object -typename psobject -property $attrsht
Btw. the AzModule will be replaced by the microsoft.graph modules. So it might be the right time to do the switch, which you have to do in any case until 2024.
If you do so, you can directly get the lastSignInDateTime from the user object:
#Switch to beta API
select-mgprofile -name beta
$lastSignIn = get-mguser -userId $user.id -Property signinactivity
$lastSignIn.LastSignInDateTime
In regards to you latest comment:
once again, if you want to know the last signInDateTime for a specific user you have to filter for that user id. if you filter by companyname you will probably get several users back and then you have to loop over this array of users and query the signInLog foreach user. the problem you are facing is that you miss to specify consistensylevel and countvariable, e.g.:
$company = "MyCompanyName"
$users = Get-MgUser -filter "companyname eq '$company'" -ConsistencyLevel eventual -CountVariable $null -property Id,CompanyName,DisplayName
select-mgprofile -Name beta
$lastSignInDateTime = #(
foreach ($user in $users){
$LoginRecord = get-mguser -userId $user.id -Property signinactivity
$attrsht = #{
userId=$User.id
DisplayName=$user.displayname
CompanyName=$user.CompanyName
LastSignIn=$LoginRecord.signinactivity.LastSignInDateTime
}
new-object -typename psobject -property $attrsht
}
)
You need to have the MgGraph module installed to run the above mentioned cmdlets -> install-module microsoft.graph
More information in regards to consistensylevel:
https://devblogs.microsoft.com/microsoft365dev/build-advanced-queries-with-count-filter-search-and-orderby/

Related

foreach not exporting to csv

So i want to know how many devices a user has enrolled in azure. the script give me what i want but im having 2 problems:
i want to display every command on a different column( the user name - number of devices)
im not able to import all to a csv file.
$usuarios = Get-Content .\usersid.csv
ForEach ($usuario in $usuarios){
Get-AzureADUser -ObjectId $usuario | select userprincipalname
(Get-AzureADUserRegisteredDevice -ObjectId $usuario).count | Export-Csv -append.\cuenta.csv
}
Like #theMadTechnician mentioned, the only thing being passed to Export-CSV is the count of the devices.
You could create a Custom PS Object, build values (array of username and Devices) in the custom object and export them as a CSV.
$usuarios = Get-Content .\usersid.csv
$items = #()
ForEach ($usuario in $usuarios)
{
$username = (Get-AzureADUser -ObjectId $usuario).userprincipalname
$count = (Get-AzureADUserRegisteredDevice -ObjectId $usuario).count
$item = New-Object PSCustomObject
$item | Add-Member -NotePropertyName "UserName" -NotePropertyValue $username
$item | Add-Member -NotePropertyName "Count" -NotePropertyValue $count
$items += $item
}
$items | Export-Csv -Path D:\DevicesCount.csv -Append -NoTypeInformation

Using Objects in Powershell to do command

What im trying to do is the following:
Im getting a list of all VM`s that have some set values such as being in use and NOT having Azure Benefits turned on.
What i have is that i made a tiny script to get all machines within an subscription and select on the basis mentioned above.
What i want to do with that output is do the command Update-azureVM in bulk.
Could someone help me with this ? do i need to export the values to an excel and use that sheet to do a bulk update-AzureVM
here is the code that i have setup at the moment:
$returnObj = #()
$VMs=Get-AzVm -status
foreach ($VM in $VMs)
{
$obj = New-Object psobject -Property #{
"VmSize" = $VM.HardwareProfile.VmSize;
"VmName" = $vm.Name;
"PowerState" = $vm.PowerState;
"License_Type" = $vm.LicenseType;
}
$returnObj += $obj | select VmSize, VmName, PowerState, License_Type
}
$returnObj |
Where-Object{$_.PowerState -ne "VM deallocated"} |
Where-Object{$_.License_Type -ne "Windows_Server"} |
Where-Object{$_.License_Type -ne "Windows_Client"} |
Export-Csv C:\temp\freek.csv
Thank you all in advance!

Add Version Info to Excel file properties with VBA, read with PowerShell

My goal is to add a version number to the file properties of an Excel file that can then be read externally with PowerShell.
If I run (Get-Item "example.xls").VersionInfo I get blank ProductVersion and FileVersion.
ProductVersion FileVersion FileName
-------------- ----------- --------
example.xls
I cannot find a way to set these attributes from VBA. I did find a way to get\set a Revision Number:
Public Function FileVersion() As String
With ThisWorkbook.BuiltinDocumentProperties
FileVersion = .Item("Revision Number").Value
End With
End Function
Public Sub UpdateFileVersion()
With ThisWorkbook.BuiltinDocumentProperties
.Item("Revision Number").Value = .Item("Revision Number").Value + 1
End With
End Sub
However, I can't find a way to read the Revision Number from PowerShell. I either need to read Revision Number from PowerShell or I need to set ProductVersion and FileVersion from VBA. I would accept any combination of things that results in setting a file version in Excel that is visible outside of Excel, ideally I would like to be able to use all of these properties.
You can see the Revision Number I am trying to get from PowerShell and also the Version Number that I cannot set from VBA here:
If you right-click a file and hit properties in the Details tab, you see all that is available.
If you don't want to have to COM into the EOM (Excel Object Model), then you need to assign these in the EOM first, then hit them via PowerShell just as Windows Explorer shows them or enum metadata.
So, something like...
### Get file properties
##
Get-ItemProperty -Path 'D:\Temp' -filter '*.xl*' |
Format-list -Property * -Force
Or
### Enumerate file properties in PowerShell
# get the first file
(
$Path = ($FileName = (Get-ChildItem -Path 'D:\Temp' -Filter '*.xl*').FullName ) |
Select-Object -First 1
)
$shell = New-Object -COMObject Shell.Application
$folder = Split-Path $path
$file = Split-Path $path -Leaf
$shellfolder = $shell.Namespace($folder)
($shellfile = $shellfolder.ParseName($file))
<#
You'll need to know what the ID of the extended attribute is.
This will show you all of the ID's:
#>
0..287 |
Foreach-Object { '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_) }
# Once you find the one you want you can access it like this:
$shellfolder.GetDetailsOf($shellfile, 216)
As for this...
Thanks but your list, and the one I got from running this on my Excel
file, do not contain Revision
... try it this way.
Gleened from here:
Hey, Scripting Guy! How Can I List All the Properties of a Microsoft
Word Document?
and here:
# Getting specific properties fomr MS Word
$Path = "D:\Temp"
$ObjectProperties = "Author","Keywords","Revision number"
$Application = New-Object -ComObject Word.Application
$Application.Visible = $false
$Binding = "System.Reflection.BindingFlags" -as [type]
$Select = "Name","Created"
$Select += $ObjectProperties
ForEach ($File in (Get-ChildItem $Path -Include '*.docx' -Recurse))
{ $Document = $Application.Documents.Open($File.Fullname)
$Properties = $Document.BuiltInDocumentProperties
$Hash = #{}
$Hash.Add("Name",$File.FullName)
$Hash.Add("Created",$File.CreationTime)
ForEach ($Property in $ObjectProperties)
{ $DocProperties = [System.__ComObject].InvokeMember("item",$Binding::GetProperty,$null,$Properties,$Property)
Try {$Value = [System.__ComObject].InvokeMember("value",$binding::GetProperty,$null,$DocProperties,$null)}
Catch {$Value = $null}
$Hash.Add($Property,$Value)
}
$Document.Close()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Properties) |
Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Document) |
Out-Null
New-Object PSObject -Property $Hash |
Select $Select
}
$Application.Quit()
# Results
<#
Name : D:\Temp\Test.docx
Created : 06-Feb-20 14:23:55
Author : ...
Keywords :
Revision number : 5
#>
# Getting specific properties fomr MS Excel
$Path = "D:\Temp"
$ObjectProperties = "Author","Keywords","Revision number"
$Application = New-Object -ComObject excel.Application
$Application.Visible = $false
$Binding = "System.Reflection.BindingFlags" -as [type]
$Select = "Name","Created"
$Select += $ObjectProperties
ForEach ($File in (Get-ChildItem $Path -Include '*.xlsx' -Recurse))
{ $Document = $Application.Workbooks.Open($File.Fullname)
$Properties = $Document.BuiltInDocumentProperties
$Hash = #{}
$Hash.Add("Name",$File.FullName)
$Hash.Add("Created",$File.CreationTime)
ForEach ($Property in $ObjectProperties)
{ $DocProperties = [System.__ComObject].InvokeMember("item",$Binding::GetProperty,$null,$Properties,$Property)
Try {$Value = [System.__ComObject].InvokeMember("value",$binding::GetProperty,$null,$DocProperties,$null)}
Catch {$Value = $null}
$Hash.Add($Property,$Value)
}
$Document.Close()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Properties) |
Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Document) |
Out-Null
New-Object PSObject -Property $Hash |
Select $Select
}
$Application.Quit()
# Results
<#
Name : D:\Temp\Test.xlsx
Created : 25-Nov-19 20:47:15
Author : ...
Keywords :
Revision number : 2
#>
Point of note: I meant to add sources:
Regarding setting properties, see this Word example from the MS PowerShellgallery.com, which can be tweaked of course for other Office docs.
Set specific word document properties using PowerShell
The attached script uses the Word automation model to set a specific
BuiltIn Word document property. It is provided as an example of how to
do this. You will need to modify the pattern used to find the files,
as well as the built-in Word property and value you wish to assign.
As note above, getting is the same thing...
Get Word built-in document properties
This script will allow you to specify specific Word built-in document
properties. It returns an object containing the specified word
document properties as well as the path to those documents. Because a
PowerShell object returns, you can filter and search different
information fr
Thanks to #postanote for pointing me in the right direction. None of the code offered worked out of the box for me.
This is what I ended up doing to pull the Revision Number from my Excel document:
<# Get-Excel-Property.ps1 v1.0.0 by Adam Kauffman 2020-02-03
Returns the property value from an Excel File
#>
param(
[Parameter(Mandatory=$true, Position=0)][string]$FilePath,
[Parameter(Mandatory=$true, Position=1)][string]$ObjectProperties
)
Function Get-Property-Value {
[CmdletBinding()]Param (
[Parameter(Mandatory = $true)]$ComObject,
[Parameter(Mandatory = $true)][String]$Property
)
$Binding = "System.Reflection.BindingFlags" -as [type]
Try {
$ObjectType = $ComObject.GetType()
$Item = $ObjectType.InvokeMember("Item",$Binding::GetProperty,$null,$ComObject,$Property)
return $ObjectType.InvokeMember("Value",$Binding::GetProperty,$null,$Item,$null)
}
Catch {
return $null
}
}
# Main
$Application = New-Object -ComObject Excel.Application
$Application.Visible = $false
$Document = $Application.Workbooks.Open($FilePath)
$Properties = $Document.BuiltInDocumentProperties
$Hash = #{}
$Hash.Add("Name",$FilePath)
ForEach ($Property in $ObjectProperties)
{
$Value = Get-Property-Value -ComObject $Properties -Property $Property
$Hash.Add($Property,$Value)
}
# COM Object Cleanup
if ($null -ne $Document) {
$Document.Close($false)
Remove-Variable -Name Document
}
if ($null -ne $Properties) {
Remove-Variable -Name Properties
}
if ($null -ne $Application) {
$Application.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($Application) | Out-Null
Remove-Variable -Name Application
}
[gc]::collect()
[gc]::WaitForPendingFinalizers()
# Show collected information
New-Object PSObject -Property $Hash

Office 365 - how to manage many users

I have 200 unsorted users in office 365. I want to find an easy way to manage who they are and what security group each user belongs to.
Is there an easy way to export username and what groups each user belongs to?
Iam quite new to poweshell...
But i want to export a CSV file with user and gruops.
Is this possible?
Or do you recommend any other way to quick get an overview of all users and what grups they belong to.
Some users need to be in multiple groups and i suspect some users are missing in groups they should be in..
Thanks for any tips i can get.
################################################################################################################################################################
# Script accepts 2 parameters from the command line
#
# Office365Username - Optional - Administrator login ID for the tenant we are querying
# Office365Password - Optional - Administrator login password for the tenant we are querying
#
#
# To run the script
#
# .\Get-DistributionGroupMembers.ps1 [-Office365Username admin#xxxxxx.onmicrosoft.com] [-Office365Password Password123]
#
#
# Author: Alan Byrne
# Version: 2.0
# Last Modified Date: 16/08/2014
# Last Modified By: Alan Byrne alan#cogmotive.com
################################################################################################################################################################
#Accept input parameters
Param(
[Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)]
[string] $Office365Username,
[Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$true)]
[string] $Office365Password
)
#Constant Variables
$OutputFile = "DistributionGroupMembers.csv" #The CSV Output file that is created, change for your purposes
$arrDLMembers = #{}
#Remove all existing Powershell sessions
Get-PSSession | Remove-PSSession
#Did they provide creds? If not, ask them for it.
if (([string]::IsNullOrEmpty($Office365Username) -eq $false) -and ([string]::IsNullOrEmpty($Office365Password) -eq $false))
{
$SecureOffice365Password = ConvertTo-SecureString -AsPlainText $Office365Password -Force
#Build credentials object
$Office365Credentials = New-Object System.Management.Automation.PSCredential $Office365Username, $SecureOffice365Password
}
else
{
#Build credentials object
$Office365Credentials = Get-Credential
}
#Create remote Powershell session
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $Office365credentials -Authentication Basic –AllowRedirection
#Import the session
Import-PSSession $Session -AllowClobber | Out-Null
#Prepare Output file with headers
Out-File -FilePath $OutputFile -InputObject "Distribution Group DisplayName,Distribution Group Email,Member DisplayName, Member Email, Member Type" -Encoding UTF8
#Get all Distribution Groups from Office 365
$objDistributionGroups = Get-DistributionGroup -ResultSize Unlimited
#Iterate through all groups, one at a time
Foreach ($objDistributionGroup in $objDistributionGroups)
{
write-host "Processing $($objDistributionGroup.DisplayName)..."
#Get members of this group
$objDGMembers = Get-DistributionGroupMember -Identity $($objDistributionGroup.PrimarySmtpAddress)
write-host "Found $($objDGMembers.Count) members..."
#Iterate through each member
Foreach ($objMember in $objDGMembers)
{
Out-File -FilePath $OutputFile -InputObject "$($objDistributionGroup.DisplayName),$($objDistributionGroup.PrimarySMTPAddress),$($objMember.DisplayName),$($objMember.PrimarySMTPAddress),$($objMember.RecipientType)" -Encoding UTF8 -append
write-host "`t$($objDistributionGroup.DisplayName),$($objDistributionGroup.PrimarySMTPAddress),$($objMember.DisplayName),$($objMember.PrimarySMTPAddress),$($objMember.RecipientType)"
}
}
#Clean up session
Get-PSSession | Remove-PSSession

Change List Field with Powershell in SharePoint Online

I'm attempting to change the field contents for multiple entries in a list. So far I've gotten to the point that I can edit the list, add columns really, but can't find anything on how to edit the field text. Here is what I have currently:
EDIT:
I've found a bunch of info for 2010 which isn't applicable but I've updated the code to almost get there. I'm getting 'null array' errors when I connect to the list now. I'm hopeful because I'm able to connect, but still can't get the field to change. I've updated my if statement as well to what is I believe a better format.
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$creds = New-Object System.Management.Automation.PSCredential($User, (ConvertTo-SecureString $Pass -AsPlainText -Force));
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
Connect-SPOService -Url https://site-admin.sharepoint.com -Credential $creds
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$WebUrl = 'https://site.sharepoint.com/'
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
#Edit existing list items
$items = $List.items
foreach($item in $items)
{
if($item["Export Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete." -ForegroundColor Green
$item["Export Flag"] = "Complete"
$item.Update()
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
I am guessing you have trimmed the script since you are missing things like defining $context and such. You don't have any ExecuteQuery() calls.
MSDN doc on SP 2013 CSOM List Item tasks, which has C# examples of what you need and can be translated to PowerShell.
It generally looks like you have everything but if you could include your whole script I can try and run your script directly.
EDIT: with the updates here is the code that you need
#Load necessary module to connect to SPOService
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.Runtime") | Out-Null
#Login Information for script
$User = "user#email.com"
$Pass = "password"
$WebUrl = "https://site.sharepoint.com/"
#Connect to SharePoint Online service
Write-Host "Logging into SharePoint online service." -ForegroundColor Green
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($WebUrl)
$Context.Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User, (ConvertTo-SecureString $Pass -AsPlainText -Force))
#Get the Necessary List
Write-Host "Getting the required list." -ForegroundColor Green
$List = $Context.Web.Lists.GetByTitle("VacationRequestForm")
$Query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100);
$Items = $List.GetItems($Query);
$Context.Load($Items);
$Context.ExecuteQuery();
#Edit existing list items
foreach($item in $Items)
{
if($item["Export_x0020_Flag"] -eq "New")
{
Write-Host "Changing export flags to Complete for Id=$($item.Id)." -ForegroundColor Green
$item["Export_x0020_Flag"] = "Complete"
$item.Update()
$Context.ExecuteQuery();
}
}
Write-Host "Your changes have now been made." -ForegroundColor Green
You had a space in your Export Flag name and SharePoint will not have that in the name of the field. By default it will replace that with a _x0020_ string. This value will be based on the first name of the field. So if you change this field name in the future, you will still refer to it as 'Export_x0020_Flag' in this script. I am doing the .ExecuteQuery() for each update but you could do this once at the end of the loop. There is also the limit of 100 records in the query. If you only want records with "New" you should change the CamlQuery to just pull those records back.

Resources