Using Powershell to Pull API Information

Up until recently, I was familiar with the idea of client pulling down information from a database. A database requires updates, patching, and maintenance. Usually, I’d be the one doing all that care and feeding, additional to taking proper care of the client application. Recently I’ve been playing with api-ninjas.

API-ninjas requires a free account, and provides back to you an API key. Some of the things you can pull include:

  • Airline flight information
  • Cocktail recipes
  • Conversion of Currency
  • DNS lookup
  • Holidays
  • IP information

The list is quite exhaustive. An API is a great alternative to that pesky database maintenance above. Api-Ninja includes code on pulling the API’s in python, C#, ruby and so forth. However, it did not include anything about powershell.

Below, I’ve pasted code to get a random fact of the day:

$apikey  = "###supersecretapikey###"
$params = @{
    "Uri"  = "https://api.api-ninjas.com/v1/facts?limit=1"
    "method" = "get"
    "headers" = @{"X-API-Key" = $apikey
}
Invoke-RestMethod @Params | fl
##Sample output##
fact : A sneeze zooms out of your mouth at over 600 m.p.h

To use or change this code, change the Uri paramenter above to the value given by api-ninjas. Examples include:

https://api.api-ninjas.com/v1/cocktail?name=$input #for taking input for cocktail recipes

https://api.api-ninjas.com/v1/iplookup?address=$IP #for taking input for IP address

Azure – resetting a password for a Domain Controller VM

I came across a situation the other day.

In my Azure Tenant, I have a VM, a domain controller that hosts, well… my domain.

I only use it for testing, most recently I was doing some SSPR testing. I only turn it on occasionally for testing some powershell scripts, this password reset utility, and other things that only an on-premises Domain Controller can really do.

Over time, over about 2 weeks I didn’t need it and had this server sitting in a powered off state. When I did need it again, after powering it on, I realized I couldn’t login with my Domain Admin credentials. The error was that my password had expired, and I needed to reset it.

Okay, I’ll use my backup Domain Admin account to reset it. The problem was, the backup Domain Admin account was giving the same error.

Uh-oh.

My primary, and backup domain admin accounts to my one cloud controller that is not replicated anywhere are both locked out. Now what?

Luck has it, there’s as way to do this that’s fairly painless and actually quite simple.

  1. Create a .ps1 file. The only contents it needs are one line:
Net user AD-Admin NewP@ssword!

Name it something relevant like “password_reset.ps1”

This HAS to be an account that’s active in your AD, and perferrably a Domain Admin account. The password can be whatever you want, as long as it fits your password domain policy.

2. Goto portal.azure.com -> Storage accounts -> any_of_your_storage_accounts ->containers (create one if you have to) -> upload. Upload the .ps1 file you created in step 1 above.

3. In portal.azure.com -> Virtual Machines -> Your_VM_DC -> Settings -> Extensions + Applications -> Add a Custom Script Extension

Browse to the storage container in step 2, point to the .ps1 file created in step 1

Let the deployment run

6. Log onto your DC VM in Azure with the credentials from step 1 above. RESET any or all your domain admin passwords that have that requirement.

7. Uninstall and delete that Custom script extension from step 3 for this VM. Otherwise, every time it boots it will reset the password for this one user.

Delete that .ps1 file from the storage container too!

Azure – Import users into cloud via CSV file

There’s a few different methods to import users into your Azure tenant.

  1. In the Azure Active Directory Portal https://aad.portal.azure.com -> Users -> Bulk Operations -> Bulk create
  2. Or you can use a little powershell

This will focus on the powershell method. Mainly because the Azure Portal only requires point and click. Plus, this is way more fun.

The Sample CSV format:

UserPrincipalNameDisplayNameGivenNameSurnamejobTitleMailNickNameObjectIdAccountEnabledAgeGroupCityCompanyNameConsentProvidedForMinorCountryCreationTypeDepartmentFacsimileTelephoneNumberIsCompromisedImmutableIdMobilePasswordPoliciesPasswordProfilePhysicalDeliveryOfficeNamePostalCodePreferredLanguageShowInAddressListStateStreetAddressTelephoneNumberUsageLocationUserStateUserStateChangedOnUserType
nabendun@customdomain.onmicrosoft.comNabendu NahasapeemapetilonNabenduNahasapeemapetilon$null104667339TrueMinorSpringfieldnull United States null856-511-6827    304-960-7231    Guder Lao2810Nepali Illinois43090 Jay Drive314-812-4954US      Member
jimboj@customdomain.onmicrosoft.comJimbo JonesJimboJones$null142259518TrueMinorSpringfieldnull United States null546-298-0636    558-695-5632    Purabaya2810Hebrew Illinois39176 Weeping Birch Court851-166-3492US      Member

And here’s the sample code below.

Make sure before you run to execute connect-azureAD first!

$CSV = Import-Csv C:\path_to_CSV_file.csv -Delimiter ","
 
foreach ($User in $CSV) {
$user.UserPrincipalName
$user.DisplayName
$user.GivenName
$user.Surname
$user.jobTitle
$user.MailNickName
$user.ObjectId
$user.AccountEnabled
$user.AgeGroup
$user.City
$user.CompanyName
$user.ConsentProvidedForMinor
$user.Country
$user.CreationType
$user.Department
$user.FacsimileTelephoneNumber
$user.IsCompromised
$user.ImmutableId
$user.Mobile
$user.PasswordPolicies
$user.PasswordProfile
$user.PhysicalDeliveryOfficeName
$user.PostalCode
$user.PreferredLanguage
$user.ShowInAddressList
$user.State
$user.StreetAddress
$user.TelephoneNumber
$user.UsageLocation
$user.UserState
$user.UserStateChangedOn
$user.UserType

         Set-AzureADUser -ObjectID $user.UserPrincipalName `
         -jobTitle $User.jobtitle `
         -AgeGroup $User.AgeGroup `
         -City $User.City `
         -CompanyName $User.CompanyName `
         -Country $User.Country `
         -Department $User.Department `
         -FacsimileTelephoneNumber $user.FacsimileTelephoneNumber `
         -Mobile $User.Mobile `
         -PhysicalDeliveryOfficeName $user.PhysicalDeliveryOfficeName `
         -Postalcode $user.PostalCode `
         -State $user.state `
         -Streetaddress $user.StreetAddress `
         -TelephoneNumber $user.TelephoneNumber `
         -UsageLocation $user.UsageLocation

        write-output $User
}

How to: Configure a DNS-323 (ALT-F firmware) as an Rsync Target

The last firmware released for the DNS323 was back in 2013. That was quite a while ago, and it wasn’t great. It lacked SMB2, ssh out of the box, and no development of popular applications. I tried Alt-F on a spare DNS323 as a test to see if I could get rsync up and running.

This isn’t meant to be an expansive entry of the pro’s and con’s of this firmware. This is supposed to be a straight forward approach of configuring the DNS323 as a rsync target for backups compatible with synology dsm 6.3.

Let’s not kid ourselves, this device is pretty old. The last time it was sold any where was around 2007. As of this writing that was 14 years ago. The processor is 500MHz, it’s got 64MB of RAM, the max data transfer possible is 10MBps. I do NOT recommend putting any sort of production or super-important data onto this. I’m using this because I love to tinker, and I have an over-abundance of spare harddrives. So please, as interesting as this entry is, if you want something with performance look at a modern NAS and drives with warranty and up to date specifications!

Moving along…

The coles notes version of alt-f installation:

  1. Download the latest alt-f firmware
  2. Log into your DNS323 and apply the alt-f firmware

*I take no responsibility past this point. These instructions are recommendations, and should not be taken verbatim. This is not an official support channel. Take all the necessary precautions to backup your data beforehand.

3. Create a login password, this will also act as your ‘root’ password too.

4. Format your disks. EXT2/EXT3/EXT4 and few others are available.

It’s your choice to stick with a RAID 1/0 or JBOD. I’m using older disks and this is strictly backup for my purposes.

Create the Rsync User

Let’s create an rsync user first.

Setup -> Users

Note the full name is the “windows name”, where the nic name is the “linux login” name. Take particular note of the linux name, this is what the synology needs to initiate a backup.

Machine generated alternative text:
Full name 
Nic-k name 
user id 
G roup id 
Password 
Again

Create a folder and Share

Now we’ll need to create a share to mount the backup.

Setup -> Folders

Selected: \mnt/sdb2'backu sha 
View: Tree S Flat O 
Folder Owner Group Permissions 
500Ga dtaödtaö root 
sda2 root 
root 
O db2 root 
root

Note the mounted drives. I configured mine independently.

  • Sda2 – 500GB drive
  • Sdb2 – 1000GB drive

I gave mine a share name of “backup_share”. Then hit ‘create’.

Once created, change permissions accordingly.

backup_share: 
Can Read 
Owner 
Users in group root 
Other users 
Can Write Can Browse 
Make new files/folders inherit the group ownership O O 
Apply recursively to sub-folders 
Applv also to files 
Submit Back

With the drive folder and permissions set, now configure the share.

Services -> Network -> smb -> Configure

C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image004.png

Create a share based on the folder you created ealier

Folders Browse 
Selected: ImnVsdb2/backup_share 
View: T e C) Flat @ 
Folder: /mnVsdb2/backup_snare hit path component to visit it) 
Owner Group Permissions
C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image006.png

As a test, make sure you can browse the share from windows explorer

Ie. (\\DNS323\backup_share)

Use the username and password you created above. Make sure you can create files and folders. Notice you can enable SMB1, and SMB2 from this panel. I tried to disable SMB1, but that just made the share disappear from my Windows 10 explorer. Could be a bug they’re working out.

Side Quest – SAMBA module

There’s also an ‘Advanced’ button in Samba Setup. Use the same root password to see the contents.

C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image007.png

This panel is a bit more graphical in presentation. And gives a good representation with the ‘view’ icon of the current shares published. Spend a little time looking around, there could be some tweaks you could find useful in this section.

C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image008.png

Rsync Service Setup

Let’s setup this DNS as the rsync target.

Services -> Network -> inetdS

C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image009.png

Hit ‘configure’ on the rsync service

C:\311C66C5\BFE98FFB-6B27-4F02-B0D2-952CFF370785_files\image010.png

Configure a new folder based on the path and user you created above.

Machine generated alternative text:
- Folder Modules 
Disable 
Folder 
Browse 
Browse 
Browse 
Browse 
Module Name 
rsynrsyn 
Comment 
rsync backup directory 
Allow Browseable Read Only 
anybody
  1. It’s easier to use the built-in browser to get to your folder. Otherwise if you know it already you can enter it here. Remember, this is linux, all the directory slashes are ‘/’
  2. The module name is the viewable share name in Windows
  3. Add your comments as necessary
  4. Set permissions for the rsync account created above

Now, let’s validate the folder created above (ie. /mnt/sdb2/backup_share) exists in the rsync configuration folder. We’ll use an SSH client for this. Just regular connection with root@DNS323 works. Goto \etc and more on rsyncd.conf.

The top line should give the location of rsyncd.secrets – a password encrypted file that only rsync users should have access to.

And the bottom portion should provide the recently created directory with permissions for your rsync user.

PS C:\> ssh root@dns323-2
root@dns323-2's password:
[root@DNS323-2]# cd etc
[root@DNS323-2]# more rsyncd.conf
#Sample contents
secrets file = /etc/rsyncd.secrets
use chroot = yes
read only = yes
dont compress = *
list = yes
...

[rsynrsyn]
        comment = rsync backup directory
        path = /mnt/sdb2/backup_share
        auth users = rsynrsyn
        uid = rsynrsyn
        gid = users
        read only = no

You can tweak this to do things like host allow within a certain subnet. For this, I’m just focusing on getting rsync running.

While you’re in here, have a look at your rsyncd.secrets file. Ideally, this should only give one rsync user with password. Something like

rsynryn:password

DSM – Setup HyperBackup

Now we can create a backup job and target the DNS323 (with alt-f firmware). Create a new backup job, choose rsync as the file server type.

Backup Destination 
Please select your backup destination type. 
Synology 
folder & LJS-B 
NAS ice 
File Server

Settings should be similar to below.

For the backup settings, configure the Server type as ‘rsync-compatible server’, enter in the pertinent details of your DNS323. It should look similar to the screenshot below. For port, just keep the default 873. The Backup module, make sure to use the exact same “Path” from the rsyncd.conf file.

ie. path = /mnt/sdb2/Backup_share

Backup module = /mnt/sdb2/Backup_share

Directory = Backup_directory

And this creates a new directory of whatever name you want.

Backup Wizar 
Backup Destination Settings 
Specify the backup destination for this task. 
backup tuk 
type: 
or IP 
Tænsfer 
module: 
Di recto 
Relink to task 
dE323-2 
Ex;crt shared folder (including an deve

After this you should be able to select items to backup. Set your items, schedule them and make use of the rotational backups (very handy).

Be aware of the speeds, even if you have SMBv2 enabled, the backup jobs are still pretty slow over rsync. Still hovers around 1.2MB/s. So time your backups accordingly, and be aware that DSM Hyperbackup cannot do simultaneous backups.

-Dexter

PowerShell – Adding Proxy Addresses by CSV

This is going to be a little different. As per usual, we need to follow our regular set of steps when dealing with a large amount of data that needs validation.

  1. Export list of users into CSV format
  2. Add new values into CSV
  3. Import CSV list with values
  1. Export list of users into CSV format
get-aduser -filter * -properties samaccountname | select samaccountname,mail | Export-Csv "C:\Users_add_proxy_addresses.csv"

2. Edit the CSV with the proxy email addresses you want. The format you need is the accountname (samaccountname), and proxyaddresses (SMTP:proxyemail@email.com). Like so below:

samaccountnameproxyaddresses
rick.sanchezSMTP:rick.sanchez@newproxyaddress.com
rick.richardsonSMTP:rick.richardson@newproxyaddress.com
Codie.YoutheadSMTP:Codie.Youthead@newproxyaddress.com
You NEED that “SMTP:” portion in front, otherwise it won’t take.

3. Import the .CSV file with some code:

Import-module ActiveDirectory

$Imported_csv = Import-Csv -Path "C:\Users_add_proxy_addresses.csv"
foreach ($user in $Imported_csv)
{
    $User.samaccountname
    $User.proxyaddresses
    Set-ADUser -Identity $User.samaccountname -Add @{proxyAddresses= $User.proxyaddresses}
}
$total = ($Imported_csv).count
$total
write-host "AD accounts added with proxy addresses..."

Or , if you want to add a certain SMTP extension use this code from a SAMaccountname CSV file for all users:

$Imported_csv = Import-Csv -Path "C:\Users_add_proxy_addresses.csv"
foreach ($user in $Imported_csv)
{
    $User.samaccountname
    Set-ADUser -Identity $User.samaccountname -Add @{proxyAddresses= "SMTP:" + $User.samaccountname + "@newproxyaddress.com"}
}
$total = ($Imported_csv).count
$total
write-host "AD accounts added with proxy addresses..."

Make sure to check your work:
Get-ADUser -Filter * -Properties SamAccountname, proxyAddresses | where proxyAddresses -ne $null | select-object samaccountname,proxyaddresses | out-gridview

The above only shows ONE proxy address at a time. Since the attribute proxy-address can actually store more than one value, it’s an array.

Showing the results

The Get-ADUser cmdlet does the job nicely. Although, it’s not quite as neat as I would like:

get-aduser -filter * -properties samaccountname, proxyaddresses | Select-object samAccountName, proxyaddresses | Out-GridView

A sample output below shows the results of the proxyaddress attributes. Notice how all the different proxies are put together in the same column.

This is OK, and does require some finer tweaking with a CSV editor. However, there’s got to be a way to display each proxy address independently in their own column.

I did a little searching and I found this from the devblogs microsoft guys:

Get-ADUser -Filter * -Properties proxyaddresses | select samaccountname, @{L='ProxyAddress_1'; E={$_.proxyaddresses[0]}}, @{L=’ProxyAddress_2';E={$_.ProxyAddresses[1]}} | out-gridview

This lists out the proxy addresses by column with some help from the select statement above.

[ivory-search 404 "The search form 3350 does not exist"]

PowerShell – Changing Departments for Multiple AD Users

Hostile takeover? All employees of a department being reassigned? We won’t go into ‘how to disable way lots of employees because your upper management said ‘because we told you”. So, we’ll go into changing departments for the entire company.

There’s a few different ways to do this:

  1. Exporting to CSV, making absolutely sure who’s in the list.
  2. Or just changing everyone in one department, and replacing it with an entirely different department name.

Typically, you want option 1. This is fact checking, validation, all that stuff.

In that scenario you follow the same sort of methodolgy:

-Export all users that meet the criteria (in this case, everyone of a certain department) into a CSV file

-Take CSV file, inject into powershell and set new value

There is also a ‘once and done’ approach. Where you can simply replace the values in one string. I don’t suggest this for production environments, namely because there’s always a margin for error.

The ‘typical’ option

Export all users that fit a filter into a CSV file. In this example, I’m looking for all AD users with Department ‘Support’. Exporting to a CSV file. Export something unique, like the samAccountName.

Get-ADUser -Filter 'Department -like "Support"' -Properties * | select samaccountname | Export-CSV "C:\Path_to_csv\department_users.csv"

With this exported file “department_users.csv”, we use another piece of code to pick up the CSV file, run a for-loop to go through each user in that CSV file and update their department.

Import-Module Active Directory

$Set_Department = Import-Csv "C:\Path_to_csv\department_users.csv"  #Store CSV file into $Set_Department variable
$Department = "Operations Support" #New Department

foreach ($User in $Set_Department) {
    #For each name or account in the CSV file $Resetpassword, reset the password with the Set-ADAccountPassword string below
   $User.sAMAccountName

        Set-ADUser -Identity $User.sAMAccountName -Department $Department
        write-output $User
}
 Write-Host " Departments changed "
 $total = ($Set_Department).count
 $total
 Write-Host "AD User Departments have been updated..."

Just make sure your end CSV file has a format of only the SamAccountname (like below).

sAMAccountName
Zuzana.Burris
Zandra.Caig

The ‘Once-and-Done’ Option

Again, I don’t suggest this unless you feel absolutely comfortable with the results. If, however you’re in a hurry and need to change all attributes to the new updated attribute, this is the line of code for you.

Get-ADUser -Filter 'Department -like "Old Department Name"' | Set-ADUser -replace @{department="New Department Name"}

As always, you can retrofit this code to suit your needs.

You could also change other AD attributes with this sort of syntax as well, just be sure to change your code, and TEST first.

Showing the Results

Let’s see which AD Accounts by SamAccountName, Department and Title have a specific title. We’ll say anything with a title of “Support”.

Get-ADUser -Filter 'Department -like "*Support*"' -Properties * | select samaccountname, department, title | out-gridview

Or you could search for all users that do NOT have a department specified

Get-ADUser -Filter * -Properties * | select samaccountname, Department,title | where department -eq $Null
[ivory-search 404 "The search form 3350 does not exist"]

PowerShell – Change passwords on multiple AD accounts

If you’re like me, you built a new AD for testing. And if you’re also like me, you imported a whole bunch of users into your AD. Some of those users likely had passwords that didn’t quite meet the domain criteria. If that happened, that means those users are disabled.

In past posts, I wrote about moving users into a different OU. Now, we’re going to change passwords for these users so we can enable them later.

For this, you’ll need a CSV in this format below. I took some liberties and retrieved a large amount of random passwords from manytools.org. There are many websites that can do this, I just like the format that manytools provided. I just pasted the passwords into the second column, the first column being the sAMAccountname of the user.

sAMAccountNamePassword
Zuzana.Burrisgz9DndwkBh8s
Zandra.Caig9eC3bcJ2SzA5

PowerShell code:

Import-Module Active Directory
$Resetpassword = Import-Csv "C:\path_to_username_password_file.csv"
 #Store CSV file into $Resetpassword variable

foreach ($User in $Resetpassword) {
    #For each name or account in the CSV file $Resetpassword, reset the password with the Set-ADAccountPassword string below
    $User.sAMAccountName
    $User.Password
        Set-ADAccountPassword -Identity $User.sAMAccountName -Reset -NewPassword (ConvertTo-SecureString $User.Password -AsPlainText -force)
}
 Write-Host " Passwords changed "
 $total = ($Resetpassword).count
 $total
 Write-Host "Accounts passwords have been reset..."

Showing the Results

Once we’ve set the passwords, we need a way of knowing when or if the passwords were last set for a user. Referring back to the Get-ADuser cmdlet, we can look at the -passwordlastset property.

Get-ADUser -filter * -properties passwordlastset | sort-object samaccountname | select-object samaccountname, passwordlastset, passwordneverexpires | Out-GridView
[ivory-search 404 "The search form 3350 does not exist"]

PowerShell – Move AD users via CSV file

This is part of my ‘Finding all Disabled users in AD’ from an earlier post. The backstory is, I used some powershell to import about 1100 dummy users into a newly created AD.

Out of 1100 users, 300+ became disabled due to non-compliant passwords (too short, didn’t meet requirements). My end goal was to have all disabled users re-enabled, which meant I had to give them all proper passwords. In the meantime, I decided to create this script to move all disabled users into a separate OU.

The steps for this script are pretty simple:

  • 1. Create a list of all the disabled users (done in last post)
  • 2. Export list of disabled users, taking all the unique values (samAccountName) into .CSV Format (done in last post)
  • 3. Retrieving the list with powershell, and moving all the users in the CSV list into another AD OU container

This does of course require a list of users in CSV format, just SamAccountName since each user has as unique value.

like so:

SamAccountName
“Codie.Youthead”
“Bellina.Kobierski”
“Melitta.Marcum”
“Marietta.Caverhill”
Sample CSV file contents

Now the code:

import-module ActiveDirectory
#Store CSV into $Movelist variable
$MoveList = Import-Csv -Path "C:\Path_AD_users_to_move.csv"

#Specify target OU to move users in that CSV file
$TargetOU = "OU=Disabled-Users,OU=contoso,DC=contonso,DC=org"

#Import the data from CSV file and assign it to variable 
$Imported_csv = Import-Csv -Path "C:\C:\Path_AD_users_to_move.csv"

$Imported_csv | ForEach-Object {
     # Retrieve Distinguised Name of Users
     $UserDN  = (Get-ADUser -Identity $_.SamAccountName).distinguishedName
     Write-Host " Moving Accounts ..... "
     # Move user to target OU.
     Move-ADObject  -Identity $UserDN -TargetPath $TargetOU #-Whatif
     
 }
 Write-Host " Completed move " 
 $total = ($MoveList).count
 $total
 Write-Host "Accounts have been moved successfully..."

Showing the Results

Typically, Get-ADUser relies on the -DistinguishedName Property. Which really is quite long, and not entirely human readable. Sample code which works, but not in a very pretty manner:


Get-ADUser -Filter * -Properties * | select samaccountname,DistinguishedName|sort-object -descending DistinguishedName

Not really the best use of screen real estate

The distinguishename property by itself is a string, separated by a comma “,”. Which means, we can actually split the contents by still using one line of code within powershell. Like so:


Get-ADUser -filter * -Properties samaccountname,distinguishedname | select samaccountname, @{l='OU';e={$_.DistinguishedName.split(',')[1].split('=')[1]}}

Results show like so:

I can’t seem to get the sort-object code to sort by distinguishedname. If someone out there knows how, I’d be happy to include it in here.

[ivory-search 404 "The search form 3350 does not exist"]

PowerShell – Finding all Disabled users in AD

Need to find all the disabled users in your AD? it’s odd that the built in AD Tools do not have this option. PowerShell to the rescue!

All these commands are documented in the Microsoft Get-ADUser cmdlet. I’ve added some additional types of output with out-gridview and CSV.

Finds all the disabled users in AD.

Get-ADUser -Filter {Enabled -eq $false}

Finds all and outputs to a gridview for editing (but you need excel)

Get-ADUser -Filter {Enabled -eq $false} | Out-GridView

Finds all disabled users and outputs to a CSV file. This exports ALL the readily available attributes.

Get-ADUser -Filter {Enabled -eq $false} | export-csv "C:\users\Administrator\Desktop\disabled_ADusers.csv"

Finds all the disabled users by specific property and selects the objects and outputs them

Get-ADUser -Filter {Enabled -eq $false} -properties SamAccountName,mail | Select-Object SamAccountName,mail | Out-GridView

Finds all the disabled users, looks a properties that aren’t readily available like email, export to a CSV file

For some reason, you can’t search by mail address outright or have it display, you have to select it, then show it with that select-object command

Get-ADUser -Filter {Enabled -eq $False} -Properties SamAccountName,mail | Select-object SamAccountName,mail| export-csv "C:\Path_to_CSV.csv"

Or you can use variables to clean up the code:

$SamAcc = "SamAccountName"
$Desc = "Description"
$mail = "mail"
$title = "title"
$CSVpath = "C:\Path_to_CSV.csv"

Get-ADUser -Filter {Enabled -eq $False} -Properties $SamAcc,$mail | Select-object $SamAcc,$mail| export-csv $CSVpath
[ivory-search 404 "The search form 3350 does not exist"]