Wednesday, November 27, 2024

Boox Color 7 + Kindle App Set Book Cover As Screensaver or Background

Problem:

You got the Boox Color 7 as an upgrade or alternative to the Kindle Color but you can't set your sleep or power off screen to the title of your active book

Cause:

It's a built in feature of the Kindle devices and they can't control your Boox Android system...but you can.

Resolution:

Go to Settings - GESTURES area and make one of the swipes (I prefer swipe from left) the Screenshot option (NOT THE AREA SCREENSHOT). Then, open your Kindle app, view the cover, and swipe with your single finger from whichever direction you just set and wait a couple of seconds. When the screenshot menu appears, just tap the check mark. Finally, go to the Gallery app, open screenshots, tap your cover, and tap the More at the bottom right and choose Set As to set your book cover as Screensaver and Power Off images.

I know it's a couple of steps, but really not bad unless you're a speed reader or you read multiple books at a time and want it automatic...to that I say buy a Kindle.

Tuesday, June 11, 2024

Connect to Azure (Connect-AzAccount / Connect-PnPOnline) using certificate from Azure Automation or KeyVault

Situation: You want to connect to Azure using a certificate file (typically a PFX file) in a PowerShell script, especially in an unattended scenario (e.g. Azure Automation) or a multi-tenant environment.

Problem: Connect-AzAccount (and Connect-PnPOnline and other cmdlets) don't yet (as of 2026-06-29) allow the use of x509 certificate objects, only a CertificatePath that you must specify to a local store OR a CertificateThumbprint that indicates that you installed the certificate on the local computer. AND you don't want to use a managed identity for an entire Automation Account or similar.

Resolution: You can use PowerShell commands to perform the following steps to make it work -

  1. Get the Certificate file and a credential of some sort (usually a service principal involved in the process anyway)
  2. Export as password-encoded certificate PFX file to a temp folder on the local machine (this works on Automation workers as well)
  3. Connect to AzAccounts using the temp path and the password.
You can view my commands below as they aren't a full script and thus not in my github. My scenario is to use Azure Automation's Certificates and its Credentials section to store a service principal account password securely, the Cert securely, and leverage the Credential password to secure the file, disconnect from the automatic Automation Az connection, and connect with the certificate. This is all done within a Runbook. If you needed to do this from a KeyVault, then you would need to obtain the Certificate from the Vault and include the private key in the particular x509 object you retrieve:

$Credential = Get-AutomationPSCredential -Name "MyServicePrincipal"
$Tenant = "YOURTENANTGUIDGOESHERE"
$ApplicationId = "YOURAPPLICATIONIDGOESHERE"

#Prep azure connection by getting cert, exporting to local temp file securely, then using for Az connection
$Cert = Get-AutomationCertificate -Name 'MyAppCertificate'
$CertTempPath = "$env:TEMP\temp.pfx" #You can name it dynamically if you like

try {
    $PfxCert = $Cert.Export(3,$($Credential.GetNetworkCredential().Password))
} catch {
    $Msg = "Error exporting cert - $_"
    Write-Error -Message $Msg
    Disconnect-AzAccount *> $null
    throw $Msg
}
if (Test-Path $CertTempPath) {
    Remove-Item -Path $CertTempPath
}
try {
Set-Content -Value $PfxCert -Path $CertTempPath -Encoding Byte #<-- PS 5.1
    #Set-Content -Value $pfxCert -Path $certTempPath -AsByteStream #<-- PS 6+
} catch {
    $Msg = "Error setting content - $_"
    Write-Error -Message $Msg
    Disconnect-AzAccount *> $null
    throw $Msg
}
try {
    $CertArgs = @{
        CertificatePath = $certTempPath
        CertificatePassword = $Credential.Password
        Tenant = $Tenant
        ApplicationId = $ApplicationId
    }
} catch {
    Write-Error -Message "Unable to get Automation Cert info - $($_.exception.message)";
    Disconnect-AzAccount *> $null
    throw
}
try {
    Disconnect-AzAccount *> Out-Null
    Write-Output -InputObject "Disconnected from Az. Connecting using $($Credential.UserName)..."
    $context = Connect-AzAccount @CertArgs -ErrorAction Stop
    Write-Output -InputObject "Done"
} catch {
    Disconnect-AzAccount *> Out-Null
    throw "Unable to connect to AzAccount using supplied Credential"
} #DO STUFF HERE LIKE GET-AZADUSER OR SOMETHING Disconnect-AzAccount *> Out-Null #Always close out your sessions properly Remove-Item -Path $CertTempPath #Remove the PFX file so it is unobtainable

Tuesday, April 16, 2024

Powershell Active Directory Permissions Report

 Problem: You need to find out what kinds of access a user or group has in your *GIANT* Active Directory environment. Maybe not so giant, but still.

Cause: Active Directory permissions reports are a pain to build and often get farmed out to third party vendors and you don't want to or can't get said reports to make them pretty.

Resolution: Use my script. What it does: When run in powershell (only tested in 5.1 but should hopefully work in 7.2/7.4), the script finds the AD Forest that the current computer is a part of, gets the domains, scans for objects (of the types you want), and then gets ALL permissions, optionally then filtering them for a user or group. You can even find out what a person *could* do by also including their group membership - this is often a hidden weakness because you can't see anything with the user listed directly. I hope you find this helpful, it took me a while to get right.

https://github.com/hornerit/powershell/blob/master/Get-ActiveDirPermsReport.ps1

Sample input: .\ActiveDirPermsReport.ps1 -UserOrGroup hornerit -ObjectsToScan OUs

Sample output:



Tuesday, March 19, 2024

Azure Automation Hybrid Runbook PSPrivateMetadata missing or broken

Problem: You have a Windows-based Hybrid Runbook Worker configured with PowerShell 7.2+ connected to Azure Automation and a runbook fails to find the Job ID or cannot find the PSPrivateMetadata variable.

Causes:

  • In PowerShell 7.2, it treats the PSPrivateMetadata as an environment variable, so it is in the ENV path.
  • Your version of the hybrid runbook worker extension stopped treating the ENV:PSPrivateMetadata as an object and displays it only as "System.Collections.Hashtable" instead of an *actual* hashtable (still an issue as of 2026-06-29).

Resolution:

  • If your 7.2 runbook needs the PSPrivateMetadata, just replace it with $ENV:PSPrivateMetadata. Note that with PS 5.1, you would often get the GUID as $PSPrivateMetadata.JobId.Guid...when you switch to 7.2, it supplies the guid as a string so you only need $ENV:PSPrivateMetadata to get the job id.
  • If the issue is your extension, you have to accommodate it differently - you have to use the contents of the trace.log file in your runbook worker that is auto-generated for your runbook's run and THAT should contain the jobId...I used a variant of the solution from Rakesh (you can google this issue and you'll see his solution) but am working on one that will be smart and let me do the thinking in a powershell module or script function.

Thursday, February 24, 2022

Bulk DNS Management in PowerShell

So your environment got bigger fast and you have a TON of forward and reverse lookup zones and something is out of whack. Well, I have a tool I've made in PowerShell and used successfully to 1) Find DNS A and PTR records related to specific hostnames or IPs and 2) Update their records like adjusting TTL and bulk renaming to point to a new host and 3) Make a backup of the existing records just in case as a CSV file ^_^).

This is probably one of the scariest tools I've had to build and comes with ZERO warranty - because, seriously, this is manipulating DNS records in bulk - but if you want to even just check to see what A or PTR records exist for a single IP then this might help you. You just run the tool as an admin on a Domain Controller, it IS interactive, and it will tell you that it may take several minutes to retrieve all A and PTR records and mesh them together. After that, it presents a menu to work with. I'm always open to tweaking ideas like I want to, at some point, have an option to just delete all orphaned objects or force re-create PTR records for all A records that are missing them...but that gets weird when you have load balancers and web apps where a ton of stuff should or should not point to one IP. Have fun!

Requires the DNSServer module from RSAT and to be run locally as an admin on the DC. Here's the link to the script:

hornerit/powershell (github.com)

Tuesday, October 20, 2020

Office 365 Spam Remover - Now supports MFA (Updated to support Content Searches)

Problem: A spam campaign has hit your tenant and affected mailboxes and the Campaign options in O365 are either unavailable or don't satisfy the executives yelling at you while you read this.

Resolution: Adjust this script to replace CONTOSO with your domain (if not it will prompt you). This will prompt you for your Exchange Admin credentials, offer you the chance to add more exchange admin accounts to run this under, prompt for the evil sender(s), date and time the spam campaign hit, and optionally the subject line(s) of the evil email messages so you don't accidentally remove too many messages. The script uses a message trace of all email sent to your tenant by the evil senders during the time frame specified and then searches those mailboxes to find the message(s) and NOW CREATES CONTENT SEARCHE(S)! From there, it will create the Purge action necessary to delete the message in question.

Last Updated May 21, 2019 to improve several sections based on feedback and optimizing. Another version of this script has been posted that has a GUI for all of the initial input using the Windows Presentation Framework built into Windows (so no special installs needed) at https://www.hornerit.com/2019/05/o365-spam-remover-script-now-with-gui.html. As with any script you get from the internet, no warranty is expressed or implied for this script so test it and tweak to your environment. I have tried to make it use UTC and avoid hard-coding any regional settings but your mileage may vary.


Update 2019-06-17 - I have moved my scripts to a github repository so that updates are easier to make. DO NOT WORRY - I do not make my github look freaking weird with folders and cryptic things that non-developers don't understand...my scripts are right there in the main folder and you can click them to view/copy/download: https://github.com/hornerit/powershell/blob/master/O365-SPAM-REMOVER-NoGUI-Public.ps1

O365 Spam Remover Script - now with a GUI and supports MFA (updated to use Content Search)

Problem: A spam campaign has hit your company and you want to remove the email from all inboxes in the tenant to help prevent people clicking bad links, freaking out, etc.

Solution: I've created a script as an update to the original script for this post. The newer ExchangeOnlineManagement powershell options appeared and the Search-Mailbox cmdlet has been deprecated...so, the new version creates a Content Search and also creates the appropriate purge actions to delete all email. This script will try to load a GUI for you with several options to control the senders, subject lines, and time frames the spam campaign was sent to make it much simpler on you to remove that phishing or spam campaign that made it through. If the GUI fails, it will fail back to an interactive cmd line script requesting the same info. As with any script you get from the internet, no warranty is expressed or implied for this script so test it and tweak to your environment. I have tried to make it use UTC and avoid hard-coding any regional settings but your mileage may vary.


https://github.com/hornerit/powershell/blob/master/O365-SPAM-REMOVER-GUI-Public.ps1

Update 10/20/2020 - The code has been overhauled and updated for content searches! Update 6/17/2019 - Moved the code to GitHub for easier updating. DO NOT WORRY - my github does not look like some giant mess of folders with cryptic things...the powershell files are right there on the screen and you can click any of them to view them in their entirety.

Update on May 22, 2019 - I have added some support to attempt to auto-load the Exchange Online for Powershell module and use it as priority over basic authentication.

Thursday, February 6, 2020

PowerShell Scripts - Get all Mailbox and Mailbox Folder permissions in O365 (New Exchange PowerShell)

Script updated several times between 2020-02-10 and 2020-03-5 to tweak different aspects when using the new Exchange Online powershell cmdlets that is currently in preview but is generally much more efficient for this task along with code readability and documentation updates. I received confirmation that getting mailbox folder permissions will return something more than a displayname and that we will eventually be able to use the FolderId instead of folder path since folder paths have problems with backslashes and other foreign characters.

Problem:
You need to document, monitor, and manage mailbox and mailbox folder permissions across an entire O365 tenant. When trying with PowerShell, we can't even pipe Get-Mailbox to Get-MailboxFolderStatistics to Get-MailboxFolderPermissions. When attempting these things in PowerShell, it has traditionally been extremely slow.

Source:
This gets weird when it comes to mailbox permissions (FullAccess, SendAs, SendOnBehalf), Calendar Permissions, and Mailbox Folder Permissions (tons of options) and HR wants you to verify that an employee does not have access to that mailbox even if they are rehired later. The old Exchange PowerShell commands transmitted too much data so the results of pulling large numbers of mailboxes and folders were too slow to be feasible. One could search the Unified Audit Log for folder permissions changes but that doesn't give the baseline.

Resolution:
You can download my interactive script that does the retrieval, partial retrieval, and resuming here: https://github.com/hornerit/powershell/blob/master/Get-O365MailboxPermissionsAcrossTenant.ps1. I have updated several times and maintain updates on it for tweaking special scenarios and will update once the new cmdlets offer different data.

No matter how you try, you will need to make a local copy of the mailbox/folder permissions somewhere because attempting to query this information is too time-intensive to be useful. With the advent of the new Exchange Online V2 powershell cmdlets, the performance of getting the mailbox, mailbox permissions, and folder permissions is not nearly as horrible as it was before.
Make sure you have an Exchange Admin account and you have installed the new Exchange module (Install-Module ExchangeOnlineManagement) - you can connect and even support MFA using Connect-ExchangeOnline and all the old ExchangeOnline commands still work. From there, the more straightforward version for mailbox permissions for 5 mailboxes is something like this:

Get-EXOMailbox -ResultSize 5 | 
     Get-EXOMailboxPermissions | 
     Where-Object { 
          $_.IsInherited -eq $false -and
          $_.Deny -eq $false 
     } | 
     Select-Object Identity,User,@{Label="AccessRights";Expression={$_.AccessRights -join ","}} |
     Export-CSV -Path "C:\someFolder\MailboxPermissions.csv" -Append

Or for the Mailbox Folder permissions (for 5 mailboxes):

Get-EXOMailbox -ResultSize 5 | 
     Get-EXOMailboxFolderStatistics | 
     Where-Object { 
          $_.SearchFolder -eq $false -and
          @("Root","Calendar","Inbox","User Created") -contains $_.FolderType -and 
          (@("IPF.Note","IPF.Appointment",$null) -contains $_.ContainerClass -or $_.Name -eq "Top of Information Store")
     } | 
     Select-Object @{Label="Identity";Expression={ 
          if($_.Name -eq "Top of Information Store"){
               $_.Identity.Substring(0,$_.Identity.IndexOf("\"))
          } else { 
               $_.Identity.Substring(0,$_.Identity.IndexOf("\"))+':'+$_.Identity.Substring($_.Identity.IndexOf("\")).Replace([char]63743,"/")
          }
     }} | 
     Get-EXOMailboxFolderPermissions | 
     Where-Object { $_.AccessRights -ne "None" } | 
     Select-Object Identity,FolderPath,User,@{Label="AccessRights";Expression={$_.AccessRights -join ","}} | 
     Export-CSV -Path "C:\someFolder\MailboxFolderPermissions.csv" -Append

Or combine them effectively (for 5 mailboxes):

Get-EXOMailbox -ResultSize 5 | 
     Tee-Object -Variable "myMailboxes" | 
     Get-EXOMailboxPermissions | 
     Where-Object { 
          $_.IsInherited -eq $false -and 
          $_.Deny -eq $false 
     } | 
     Select-Object Identity,User,@{Label="AccessRights";Expression={$_.AccessRights -join ","}} | 
     Export-CSV -Path "C:\someFolder\MailboxPermissions.csv" -Append
$myMailboxes | 
     Get-EXOMailboxFolderStatistics | 
     Where-Object { 
          $_.SearchFolder -eq $false -and 
          @("Root","Calendar","Inbox","User Created") -contains $_.FolderType -and 
          (@("IPF.Note","IPF.Appointment",$null) -contains $_.ContainerClass -or $_.Name -eq "Top of Information Store")
     } | 
     Select-Object @{Label="Identity";Expression={ 
          if($_.Name -eq "Top of Information Store"){ 
               $_.Identity.Substring(0,$_.Identity.IndexOf("\")) 
          } else { 
               $_.Identity.Substring(0,$_.Identity.IndexOf("\"))+':'+$_.Identity.Substring($_.Identity.IndexOf("\")).Replace([char]63743,"/")
          }
     }} | 
     Get-EXOMailboxFolderPermissions | 
     Where-Object { $_.AccessRights -ne "None" } | 
     Select-Object Identity,FolderPath,User,@{Label="AccessRights";Expression={$_.AccessRights -join ","}} | 
     Export-CSV -Path "C:\someFolder\MailboxFolderPermissions.csv" -Append

If you are a PowerShell person, you may notice 3 oddities with my combining:
  1. I did not use a foreach-object
  2. I used a Tee-Object
  3. There are a ton of filters and some weird Select-Object stuff going on in the middle with MailboxFolderStatistics

Foreach-Object breaks the new Exchange Online cmdlets' multithreading (speed) so I can't say Get-Mailboxes | foreach-object { Get-Mailboxpermissions; Get-MailboxFolderPermissions} ... It was actually faster to run each command separately. To keep from having to retrieve the mailboxes twice, Tee-Object allows you to take the output from the Get-EXOMailboxes, store it in a variable, and use it a second time once your first full command is over - and it does NOT break the PowerShell pipeline so speed stays happy!

The reason for all the weirdness with Get-EXOMailboxFolderStatistics is that when someone tries Get-MailboxFolderPermission but only supplies the email address of the mailbox, it only retrieves the folder permissions for the folder "Top of Information Store". So one might think - I will just use the Get-EXOMailboxFolderStatistics to get the list of all the folders within the mailbox and send THAT over to the Get-EXOMailboxFolderPermission...well, it fails miserably because the Identity of the folder from Statistics looks like mailbox@domain.com\NameOfFolder but the MailboxFolderPermissions cmdlet is expecting mailbox@domain.com:\NameOfFolder\NameofSubfolder. Right now, the FolderID is not supported in the new cmdlets, only the path. Either way, the lack of nice pairing is stupid, but fixable by Selecting the identity of folders and then fixing the name and then passing that along the pipeline. The other filters I throw in there are so that I don't ask about permissions for every dumb folder in a mailbox that might be some Teams, Yammer, etc. system folder and subfolder but I do want Calendars.

Wednesday, September 18, 2019

PowerShell Scripts - Connect to Azure AD with MFA - reusing your existing connection

Situation: You are a very good user and have Multi-factor Authentication enabled for your account and you do things in Azure often. You want to connect to Azure without having to be prompted AGAIN for your MFA once you have done so for something else (e.g. the Exchange Online PowerShell module). You could also be creating a script that many people have to run many times a day and you don't want them re-authenticating over MFA every...single...time.

Resolution:

  1. Make sure you have the latest and greatest of the Exchange Online PowerShell Module (you can get it at https://aka.ms/exopspreview)
  2. Make sure you have the latest version of the AzureAD Module (I'm using at least version 2.0.2.26 at the time of this writing)
  3. Make a script similar to this (or add to your script...this assumes the current user is the one that installed the EXO module):

    [CmdletBinding()]
    param(
        [string]$MFAPath,
        [string]$O365TenantId = "YOUR-TENANT-ID-GOES-HERE",
        [string]$O365ClientId = "1b730954-1685-4b74-9bfd-dac224a7b894",
        [string]$O365ResourceUrl = "https://graph.windows.net",
        [uri]$O365URI = "urn:ietf:wg:oauth:2.0:oob",
        [string]$DefaultDomain = "contoso.com"
    )
    Import-Module AzureAD
    #Load the MFA module.
    try{
        $getChildItemSplat = @{
            Path = "$Env:LOCALAPPDATA\Apps\2.0\*\CreateExoPSSession.ps1"
            Recurse = $true
            ErrorAction = 'Stop'
            Verbose = $false
        }
        $MFAPath = ((Get-ChildItem @getChildItemSplat | Sort-Object LastWriteTime -Descending | where-object {(Test-Path "$($_.PSParentPath)\Microsoft.Exchange.Management.ExoPowershellModule.dll") -eq $true} | Select-Object -First 1 | Select-Object -ExpandProperty fullname).Replace("\CreateExoPSSession.ps1", ""))
        . "$MFAPath\CreateExoPSSession.ps1" 3>$null
        Write-Verbose -Message "MFA module found in this folder - $MFAPath"
    } catch {
        Read-Host "MFA Module not found inside the local appdata folder for $ENV:USERNAME. If it is installed for another user already, run powershell as that user. To install the latest module, go to https://aka.ms/exopspreview. Press any key to exit"
        exit
    }
    try {
        #Since the MFA module has a file that holds all of the authentication processes, let's use that to authenticate silently
        $IdentityPath = Get-ChildItem -Path "$MFAPath\Microsoft.IdentityModel.Clients.ActiveDirectory.dll" -Recurse -Verbose:$false | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName
        Add-Type -Path $IdentityPath
        #Using the documentation for the AuthenticationContext, you need a resource url, client ID, URI (special), PromptBehavior (special), and UserIdentifier (special)
        #This means that we create a basic context pointing to a common login url for O365 but the AzureAD graph url as the resource url
        $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList "https://login.windows.net/$O365TenantId"
        #Specifying Auto for this allows MFA to check for an existing token and use it if possible, otherwise prompt for MFA
        $MFAPromptBehavior = [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]::Auto
        #Using an identifier type of 2 is required where the displayId is required for token to pass (ie the email is the username)
        $AADcredential = [Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier]::new(("$ENV:USERNAME@$DefaultDomain"),2)
        #Get the authentication...let's hope the result is successful :)
        $authResult = $authContext.AcquireToken($O365ResourceUrl,$O365ClientId,$O365URI,$MFAPromptBehavior,$AADcredential)
        #Now that all the weird auth stuff has completed, connect to azuread using the resulting data
        Connect-azuread -TenantId $authResult.TenantId -AadAccessToken $authResult.AccessToken -AccountId $authResult.UserInfo.DisplayableId
    } catch {
        write-output "Failure to connect to O365/Azure MSOLService for user account management. Here is the error from MS: $_"
        Read-Host "Press any key to exit script"
        Exit
    }
    

I learned this from a smattering of blog posts that you may also find helpful (one I found after I figured all this out on my own sadly):

Thursday, April 11, 2019

Getting around the 50k/250k limit for Azure / O365 Groups in Azure AD Sync

Problem: A giant group in your on-premises Active Directory does not sync through Azure Active Directory Sync

Source: Azure / O365 has a limit in the Azure / Entra AD Connect Sync (AAD Sync) such that it ignores groups that are over 50k/250k (depends on your version and which portion of Azure is processing groups as to their maximum size) - I even found groups really close to this limit acted weird

Resolution: Script a solution that will take your on-prem group and create mirror groups with a maximum number of users in each so that all the miniature groups will sync and auto-add/remove users from the mirror groups, and you can use these groups in Azure.

Update 2019-06-17 - I have moved this script to a github repository to make updates easier. DO NOT WORRY - it is not some crazy-looking developer page...just a list of scripts from this site. Here is the url to my repository: https://github.com/hornerit/powershell/blob/master/ActiveDirectory-SplitAndSyncGroups-Public.ps1

Azure CloudShell - Store Scripts Centrally for your Team

Problem: Cannot find or run scripts from Azure Cloud Shell that are centrally managed

Source: Azure Cloud Shell uses a secure linux vm with Powershell Core running on it and that shell has no access to any local resources (aka your file server) and you really can't connect to a git repo made by one of those fancy developers in your area - though you can clone one every time you open your cloud shell if that helps and may be good for their source control...I'm a sysadmin, I don't really get the git mantra except for backups. Also, many of your IT workers may attempt to access secure resources on insecure devices (aka their random personal tablet since you called them on a saturday and they don't want to VPN in using a laptop).

Resolution:

Assuming you have an AD group or Azure/O365 group that has your team members in it like we did:

  1. Log into portal.azure.com with permissions to create stuff in your subscription
  2. Create a Resource Group for your team in the same location as your subscription
  3. Grant Reader permissions for the team to the Resource Group (use the IAM menu option to grant this)
  4. Create a storage account with the cheapest settings possible (see below)
    1. Set the Resource Group to the one you created for your team in step 2
    2. Give it a nice, short, simple name for the Storage Account Name
    3. Set the location to the same location as your resource group (NOTE: I had problems with East US 2; if your subscription is in East US 2, choose US EAST for this)
    4. Set Performance to Standard
    5. Leave Account kind for StorageV2 (general purpose v2)
    6. Set Replication to Locally Redundant Storage (LRS) if possible, it's the cheapest
    7. Set Access Tier to Cool
    8. Use the Review and Create button and create the resource...this will take a minute
  5. Once the storage account is created, navigate to the Storage Account, and grant "Reader and Data Access" for your team
    • If you receive errors about an unauthorized header, close your browser and re-login to Azure portal
  6. Inside the storage account, click Files and create a file share, call it something like "share", don't set a quota - every new user that accesses CloudShell and creates a profile will commit 5gb to this share so there's really no point in trying to limit unless you are scared of the hackers
  7. Click the "share" share so that it opens and click "Upload" and upload scripts and other resources here for your team
To access these resources, you need to have your each member on your team open a new Cloud Shell and, hopefully, they've never used this before. If they have, you will need to have them use a command to mount this new storage instead of their original storage (clouddrive mount -s SUBSCRIPTIONGUID -g "YOURRESOURCEGROUPNAME" -n "YOURSTORAGEACCOUNTNAME" -f "YOURSHARENAME")...beware, they may want to backup their stuff before they switch storage like that:

  1. Click the Cloud Shell button immediately to the right of the search bar in Azure Portal
  2. Click PowerShell as the language (you can change this later if you like)
  3. Click Advanced Settings on the right
  4. Make sure the settings all match what you have made (you may have to manually type the Share name)
  5. Click Connect/Yes/whatever allows it to go
Now that it is connected (you can verify if you use the Get-Clouddrive command and it gives you useful information), you can access those shared resources by typing this:
cd $HOME/clouddrive
Now your PowerShell window is located in the main directory of the share...you can use dir to list the contents and even use tab completion to load your script name and it'll work. One downside: you cannot access local resources (e.g. local Active Directory or modules) when the script is accessed within cloud shell (you can actually map it as a network drive). The best way to handle this situation is to create a Hybrid Runbook Worker so that you can create Runbooks (aka scripts) and use the scripts stored in your shared location to call the runbooks and specify that they run on the Hybrid Runbook Worker.

Thursday, November 30, 2017

Extract Attachments Inside or Embedded Within InfoPath XML Forms

SITUATION: It's been a while but I'm back to working more with SharePoint - YAY - and was hit with my first unique request back in 2018: we want to find a way to extract files that are embedded inside of InfoPath attachment controls. Along the way, also had to figure out how to download all files in a library.

RESOLUTION: I apologize now: THERE IS NO OOTB WAY TO JUST GRAB THESE SUCKERS...you must use SOME form of code or script :(. So, I figured out two ways originally and have maintained one way to do this: PowerShell. This way, you can download the files locally and then extract the attachments (does use more disk space) but is probably done on a SharePoint admin server - I welcome some assistance in porting this to O365 so that anyone can run this on their own computer if they have appropriate perms

******CAVEATS******
The ways presented are definitely a beta and should be applied only to a test instance of SharePoint so you don't kill your server or computer. I'm definitely not responsible for you using this script and it messing stuff up - review it, test it, follow your company's standards for verification and testing, etc.
I welcome feedback if you discover a bug in it but feel free to use how you see fit, tweak it, whatever. It'd be nice to keep some credit if you end up doing amazing things with it - just let me know :)!
This was tested using PowerShell on a SharePoint Server 2010 instance. This may or may not work in other versions, I'm sure you could test it and let me know.
******END CAVEATS******

Now, it took me a while to get all the pieces together, so here are the links to the information needed to pull this off <begin credits>:
  1. MS explains how to do this in visual studio code here
  2. Chris White expounds on the same thing in some different detail here
  3. Different stack exchange questions related to pushing and pulling from XML in a form library as well as handling the attachment raw data and rebuilding it here, here, and here
  4. Masanao Izumo has a cross-browser implementation for converting an unsigned 8 byte integer array back to a string (text) here
  5. (2022 update) - MS has some documentation on the byte header that they insert before files that have been embedded within their xml files here <end credits>
Powershell Script - Most recent update was 2022-05-02. Has 2 requirements and 3 optional pieces for which it prompts: 1) URL of the sharepoint web (aka the regular site, not site collection), 2) The name of the form library, and 3) if you are extracting InfoPath forms, what data source in the xml file do you want to use to create folder(s) on your computer in which to place all of the attachments - if it is an XML attribute instead of a proper data source then that is ok too, and 4) and 5) a cutoff date in case you want to only download items before a certain date or after a certain date. The last part that you *might* edit is the $filepath since that is the main path on your computer for where you want to stick all these attachment files. Here's the script link: https://github.com/hornerit/powershell/blob/master/Get-SharePointInfoPathFilesAndAttachments.ps1

Further Explanation: So here's how it pulls together:

  1. InfoPath XML attachment files are first a long string that has been "encoded" into something called Base64. You don't have to know what that means, you just have to know they were encoded - which means to use them we need to decode them. That's the first step once we have the InfoPath XML file.
  2. The attachment files (once decoded) are composed of a header portion and the data portion. The header consists of 2 parts: a fixed header set of information and the filename of the attachment.
  3. Byte 20 of the header tells you just how long the filename is as a number. This is a byte but needs to be doubled for how the information is encoded (unicode or UTF8).
  4. Once we know how long the filename is, we look *just* past the end of the regular, fixed header (byte 24) and copy every other byte till the end of the filename section - except for the very last one as it has a byte to tell the system that this is the end of the file name. The reason we do every other is that the ones in between are basically nothing or what programmers call 'null'. One weird thing - PDFs in my environment didn't have a file extension at the end of their name...so I created a small workaround to just append .pdf if there was not any extension mentioned.
  5. Now that we have the filename, we need to separate out the contents from the header, so we create a new array that just starts after the end of the filename.
  6. This new array needs to be somehow converted into a file...in *Windows* Powershell, we use the WriteAllBytes function to make it a file and we just tell it where the path is that it should write and give it this blob of goodness
  7. Getting access to the file itself is easy for Powershell - when the script is done, go look at your folder. There's the "_DownloadedRawFiles" subfolder, which you can ignore for now, and there's all the other folders generated by the extraction process based on the group by aka Folder Structure Node supplied.

Monday, April 7, 2014

Android Home Button keeps opening recent apps

Problem: I have a Galaxy S4 and at some point it decided that when I press the home button on the phone it would always open up the recent apps window - even if I didn't hold the home button down! This got frustrating but I started adapting to double-hitting the home button all the time.

Resolution: Found out when working on my wife's phone - this started happening to her after installing the Dolphin browser. So I fiddled with it and I figured it out - Dolphin's "Confirm before exit" setting was causing it, turn that sucker off and restart your phone!

TL;DR/To fix - open Dolphin, go to Settings, then Exit Settings, then turn off the "Confirm Before Exiting" setting. Restart your phone and BOOM. Worked for me. Others have also mentioned that they noticed this happening when using the Samsung Keyboard or the Samsung preinstalled Swype instead of the Google keyboard or the full Swype+Dragon app.

Thursday, March 6, 2014

SharePoint 2013 Workflow App Step won't work, gets suspended

Situation: SharePoint 2013, Workflow Manager 1.0 + the two CUs for Service Bus and Workflow Manager, List with workflow that has an app step (to allow it to read/write to other lists to which the user does not have access). Workflow App Step can't seem to do anything at all! Tried process of elimination and it seems like it cannot look up any field in my current item. When I look at the workflow right after it starts, the status says "Starting" with this message in the little "i" symbol:

Retrying last request. Next attempt scheduled in less than one minute. Details of last request: HTTP NotFound to https://MYSERVER/_vti_bin/client.svc/web/lists/getbyid('SOME_GUID_GOES_HERE')/Items(IdOfYourItem)?%24select=SOMETHING

After that, it gets a status of "Suspended" with detail in that little "i" icon of something awful like this (which is a web service result from that client.svc mentioned up there):
Details: An unhandled exception occurred during the execution of the workflow instance. Exception details: System.ApplicationException: HTTP 404 {"error":{"code":"-1, System.ArgumentException","message":{"lang":"en-US","value":"Item does not exist. It may have been deleted by another user."}}} {"Transfer-Encoding":["chunked"],"X-SharePointHealthScore":["0"],"SPClientServiceRequestDuration":["18"],"SPRequestGuid":["c38c92af-563c-073b-8950-19e9ab5d00ce"],"request-id":["c38c92af-563c-073b-8950-19e9ab5d00ce"],"X-FRAME-OPTIONS":["SAMEORIGIN"],"MicrosoftSharePointTeamServices":["15.0.0.4420"],"X-Content-Type-Options":["nosniff"],"X-MS-InvokeApp":["1; RequireReadOnly"],"Cache-Control":["max-age=0, private"],"Date":["Thu, 06 Mar 2014 22:07:22 GMT"],"Server":["Microsoft-IIS\/7.5"],"X-AspNet-Version":["4.0.30319"],"X-Powered-By":["ASP.NET"]} at Microsoft.Activities.Hosting.Runtime.Subroutine`1.SubroutineChild.Execute(CodeActivityContext context) at System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

Resolution: Turns out, the App Step can't get past those pesky list advanced settings where you set "item-level permissions" to "Read only their own". Yea, for that the workflow "app" would need to have higher or elevated permissions. Seems like the only way to do this is to A) Have an app catalog and B) Set the workflow "app" as having full control using a hidden app permissions page. You can find the step by step here (Microsoft) or here (Fabian Williams...the better one if you ask me). This applies to any action that might require full control or design-like permissions like creating lists, creating sites, etc. and applies to SharePoint 365 as well.

SharePoint 2013 List Not Shared With You

Situation: SharePoint 2013, claims-based authentication using Windows NTLM claims (aka your Windows PC passes your username and password to SharePoint's claims security service to log you in), site uses AD group membership to control access, and finally a web part on the homepage to show some items in this list.

Other users could load this just fine, my user would get no items and, when I clicked on the list itself, would get "Sorry, this site has not been shared with you" (nevermind that it was a list, not a site, the error still said 'site'). Checked permissions on the item, list, site, site collection, masterpage library, themes libraries, web parts, image library, custom javascript library pages, etc. Checked server logs and SharePoint logs that show all sorts of nasty detail on every thing in SharePoint, nothing.

I also noticed that AD group membership changes didn't sync - even after telling the User Profile Service to do a full sync!

Resolution:
I remember stumbling on something about AD group memberships in SharePoint 2013 (though this applies to 2010 as well with ADFS) regarding claims-based authentication and an expiration or cache of some kind. Using two articles (here and here) with MS documentation (here, herehere, and here), I found the fix: update the Security Token Service timeout to a shorter time and update the Windows and Forms token timeouts to a shorter time as well.

Be aware - the following powershell (that you have to run from the SharePoint 2013 Management Shell) tells the STS (Security Token Service) to reduce the amount of time a user token is valid (as far as the STS cares) and then lowers the expiration timeframe for claims token handed out by the STS. This would increase network traffic (refer to articles up there for more detailed explanations) and could make your SharePoint a bit unstable if your timeouts aren't in this pattern of TokenTimeout > Windows/FormsTokenLifetimes > LogonTokenCacheExpirationWindow:

$cs = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$cs.TokenTimeout = (New-TimeSpan -hours 4)
$cs.Update()
$sts = Get-SPSecurityTokenServiceConfig
$sts.FormsTokenLifetime = (New-TimeSpan -hours 2)
$sts.WindowsTokenLifetime = (New-TimeSpan -hours 2)
$sts.LogonTokenCacheExpirationWindow = (New-TimeSpan -minutes 30)
$sts.Update()
iisreset
 
You can play with the times to be much shorter if you are just trying to fix an issue immediately but the ContentService's TokenTimeout HAS to be greater than the TokenLifetimes which HAVE to be greater than the CacheExpirationWindow. I'm playing with these settings for now and will update later if I end up changing them.

Monday, July 8, 2013

SharePoint 2010 People Picker Address Book Error - Namespace xsd not defined

Problem: You attempt to use a people picker control in SharePoint 2010 and click the little 'address book' button to find a user. You search for someone and find them (yay!) and click the OK button to add them and you get a giant error message. And then nothing. It doesn't copy the user you picked over to the People Picker or anything. When you give the error message to the admin (or you are the admin and you look up the correlation ID in the logs) then you get an error in the list saying "Namespace 'xsd' is not defined" in an XML error.

Cause: Customizations to SharePoint masterpage to make it use more recent web technologies like CSS3/HTML5 (via the X-UA-COMPATIBLE meta tag) OR your browser trying to force a square peg (IE8 stuff) into a round hole (IE9 or 10+ browser).

Resolution:
Sadly, if there are customizations to the masterpage to try to use HTML5 or CSS3 then you have to use javascript to fix it (google for that...I think Matt Oleson had something), use a different browser than IE9 or 10, or fix the masterpage to render the page in IE8 standards (re-setting the X-UA-COMPATIBLE to IE8 instead of IE9 or EDGE or anything else that might be there).

If, however, you have done no customizations of this modern sort in your environment and you are using IE9 or IE10 and you get this then your problem is a lack of compatibility view. You need to add your SharePoint site to your IE list of sites in the Tools -> Compatibility View Settings. Normally, Intranet sites should be in this list (like sites inside your company network) but if the site contains a period (.) then it wouldn't qualify as an "Intranet" site in this case. We used GPO (Group Policy Objects) to push this setting out to all computers in our environment to force IE to see our site in Compatibility View.

Thursday, June 27, 2013

SharePoint Designer 2010 Workflow - Lookup User Information in SharePoint Foundation 2010

Problem: In Foundation 2010, SharePoint Designer only allows you to perform a lookup on a user's Name, Display Name, Email Address, and ID...what about custom fields that were added to the User Information List? What about Department, Phone number, or any other field that works fine with a People Picker? Can I do ANYTHING without going into dreaded code or installing a third-party app or upgrading to Enterprise's User Profile Service? The answer is yes, in VERY limited circumstances (so don't get your hopes too high yet)

Resolution:
Caveats:
  • This will ONLY work on the root site of a site collection (believe me, tried this in many ways but it seems you cannot change the WEB property of a workflow context on the fly)
  • This requires SharePoint Designer, should be obvious but wanted to mention just in case
  • The getting of your User Information List GUID (first step) can be accomplished in several ways but almost all of them will require site collection administration privileges
  • What you are essentially going to do is create a dummy User Information List with the columns you want in it, get your workflow working beautifully with this dummy list based on someone's username being entered in a text field, and then do a bait-n-switch and tell SPD that the list you are using in your lookup isn't your dummy list but actually the User Information List
  • You may be able to play with it to be able to pass the User's ID to the User Info List instead of the text of the username, but it was easier for me to send it just the username from a text field
Setup:
  • Custom List that I titled "TestUserInfoList" (this is my Dummy List) with 3 columns
    • Title (didn't change it at all)
    • Username (Single Line Of Text)
    • Manager (People Picker) <-- This is my custom field to populate
  • Custom List with these columns:
    • Employee (Person or Group)
    • Manager (Person or Group)
    • Username (Single Line of Text)
  • Workflow with 2 variables:
    • varEmployee (string)
    • varManager (string)
  • Steps to workflow
    • Set varEmployee to CurrentItem:Username
    • Set varManager to (workflow lookup):
      • Data Source: TestUserInfoList
      • Field from source: Manager
      • Return Field As: As String
      • Field: TestUserInfoList:Username
      • (Fx button) -> Workflow Variables -> Variable: varEmployee
    • Set Employee to varEmployee
    • Set Manager to varManager
Steps:
  1. Get your User Information List GUID (you *might* be able to get away without this but I haven't tested it yet) 
    1. Go to your site collection homepage, and add '/_catalogs/users/simple.aspx' to the URL, and hit Enter (so your full URL would look something like http://yoursite/_catalogs/users/simple.aspx')
    2. Click on the "List View" at the top (which is a dropdown) and click "Modify this view"
    3. Take a look at the URL, you will see ViewEdit.aspx?List=BLAH&View=BLAH&Source=BLAH. What you want is to grab the 'List=BLAH', nothing before or after it
    4. Take the BLAH part and replace all the '%2D's in it with dashes (-), the '%7B' with a left curly brace ({) and the '%7D' with a right curly brace (})
    5. So you should now have the GUID of your User Information List which should look like {00000000-0000-0000-0000-000000000000} except yours will not be all zeroes
  2. Create dummy list in the root site (where you HAVE to be working), ignore the title field, create a Username field that is a single line of text, and a field with the exact same name and type as the field you wish to return (most likely a single line of text field). For my purposes, I had added a "Manager" field to my User Information List that was a people picker so that's what I recreated in my dummy list
  3. Add a couple of entries to your dummy list
  4. Create your workflow on your custom list (NOT your dummy list) and, in your first step, use the workflow to set a workflow variable (I created one called varManager) and then, in a separate step, set the field(s) in your custom list to the appropriate workflow variable and PUBLISH your workflow
  5. VERIFY THAT IT WORKS RIGHT...if you screw this part up then you'll spend hours troubleshooting later. Just make sure it works, m'kay?
  6. Again, as long as your workflow works beautifully, you are ready to trick SharePoint into using the hidden User Information List: in SPD, click "All Files" at the bottom-left, then click the "Workflows" folder in the main window, then click your workflow, and you should see at least two files, maybe 3, but the one you are looking for has the workflow symbol (a circle with a red checkbox in the middle)...RIGHT-click on this file and then click "Open With..." and choose the SahrePoint Designer -> Open as XML option
  7. You will see a bunch of gobbledeegook. It's ok, don't panic. What you are looking for is this and it will be somewhere around the 20th line of XML:
    <SequenceActivity x:Name="ID##" Description="Your Step Description where you set the workflow variables">
  8. Inside this sequence activity (which is just your step) you will look for your first ns1:FindValueActivity and it has an attribute that looks like ExternalFieldName="Username" and, further to the right, an ExternalListId="{}{0000000-0000-0000-0000-000000000000}"
  9. Replace the GUID there (leaving that first set of curly braces) with the GUID you got in step 1
  10. Go down around 5 lines and you'll see an ns1:LookupActivity where the ListId attribute looks just like the ExternalListId you just fixed...you guessed it, do the same thing to this list ID.
  11. Repeat steps 8 thru 10 for each variable that you looked up in your workflow within this SequenceActivity. You will be essentially replacing all ExternalListId's and their corresponding lookupActivity listID's to the User Information List
  12. Save this file and close SPD.
  13. Re-Open SPD, open your site, and open this workflow
  14. Add a single action to the workflow like "Log to history list" or something, ANYTHING, and you can publish this updated workflow to your site
  15. You should be good now. To verify, delete your entries in your dummy list and create some new items in your custom list and all should work beautifully - you are now using the User Information List to set variables and use them to do your bidding...MWAHAHAHAHAHA

Thursday, December 6, 2012

SharePoint 2010 Foundation User Profile Sync

Problem:

SharePoint 2010 Foundation does not provide a user profile synchronizing service between active directory and SharePoint. Sure, whenever a user logs into SharePoint it adds that user but it only copies the name and email address and only to the site collection in question. If there are changes to the name of the user, this can sometimes get stuck and not sync over correctly. Additionally, information like the manager, phone number, and other directory information does not get pushed to the user profiles.

Why does this matter?

When you use a Person/Group column in SharePoint 2007/2010, it is really just a lookup column to that site collection's User Information List and thus you can return any column from the user information list that you like (Name, email, etc.) even though the input is always the username and click the little Check Names box. This can allow for specialized lookups in things like InfoPath or special forms where you want to automatically know who the person's manager is whenever they add an item to a list.

Enter Powershell scripting

Oh no, NO NO NO: the word "scripting" made it into a blog about 'out-of-the-box' solutions!? HYPOCRITE. Anyway, Powershell is like the command prompt from windows, something geeks have been using for years to do things that would otherwise require lots of clicks. Powershell is ONLY for system administrators, not regular SharePoint people. But this type of problem is really more of an admin problem anyway.

Resolution:

I combined two blog entries: here and here to make a script that does the following:
  1. Creates a request to pull from active directory via LDAP (lightweight directory access protocol I think). This asks Active Directory (where all usernames/passwords/etc are stored for your company) to find all users they have. Now, if your company has a bajillion users, this would be bad, but it asks for their account name and just a few properties so it's not too terrible (and, hey, I have like 80 users to deal with it).
  2. Gets all the site collections from SharePoint
  3. For each site, try to run a simple "SyncFromAd" command to make sure that the user's automatic info is up-to-date
  4. Go the user information list and update the columns in there with my information
  5. Forgot to mention - I added a couple of custom columns to the user information list for my site collection...that may be a no-no, not totally sure ^_^, but I SET THEM ANYWAY. Bam.
So, without further ado, here's the script that does the work (and this WILL take updating on your end if you want to use it to specify the domain for your company and whether or not you are adding columns to your user information lists like I did):

$objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://OU=YOUR_USERS_OU,dc=YOUR_DOMAIN_NAME,dc=YOUR_DOMAIN_ENDING_LIKE_COM")
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.PageSize = 1000
$objSearcher.Filter = $strFilter
$objSearcher.SearchScope = "Subtree"
$varDomain = "YOUR_DOMAIN_NAME"

$colProplist = "samaccountname","title","department","ipphone","mobile","name","distinguishedname","manager"
foreach ($i in $colPropList) {
 $objSearcher.PropertiesToLoad.Add($i)
}

$colResults = $objSearcher.FindAll()
$manResults = $objSearcher.FindAll()
$sites = Get-SPSite -Limit "ALL"

foreach ($objResult in $colResults) {
 $objItem = $objResult.Properties
 write-host 
 $userID = $varDomain+"\"+[string]$objItem.samaccountname
 foreach ($site in $sites) {
  $web=$site.RootWeb
  set-spuser -Identity $userID -SyncFromAD -web $site.url -ErrorAction SilentlyContinue
  if(!$error[0]) {
   write-host $site.url " - " $userID
   $list = $web.Lists["User Information List"]
   $query = New-Object Microsoft.SharePoint.SPQuery
   $query.Query = "<Where><Eq><FieldRef Name='Name' /><Value Type='Text'>$userID</Value></Eq></Where>"
   foreach ($item in $list.GetItems($query)) {
    $item["JobTitle"] = [string]$objItem.title
    $item["Department"] = [string]$objItem.department
    $item["IPPhone"] = [string]$objItem.ipphone
    $item["MobilePhone"] = [string]$objItem.mobile
    $item["Title"]= [string]$objItem.name
    $item["Username"] = [string]$objItem.samaccountname
    $manager = $manResults | Where-Object {$_.Properties.distinguishedname -eq $objItem.manager}
    $managerClean = $varDomain+"\"+[string]$manager.Properties.samaccountname
    $spManager = Get-SPUser -Identity $managerClean -web $site.url
    $item["Manager"] = $spManager
    $item.SystemUpdate()
   }
  }
  else {
   #write-host $site.url " - " $error[0]
  }
  $error.clear()
  $web.Dispose()
  $site.Dispose()
 }
}

Monday, September 10, 2012

Sending emails between SharePoint lists

(Also thought of as SharePoint Workflows emailing other SharePoint Lists.)

Situation: Wanted to have a single list at the root site where users can submit ideas and problems that should go to IT for review. We figured we would place a simple list there, use the masterpage to create a link at the bottom, and have this list workflow email our own IT Tickets announcements list (different site). One problem: MS built SharePoint so that it will not recognize emails sent to it from itself (security feature for possible infinite loops- KB970818).

Resolution: There is a resolution out there that involves a VB script placed on the SharePoint server to strip out the SharePoint-y part of the email....I thought that (since I've got Exchange in my environment) I could just use what is known as a "transport rule" to strip out the same stuff so that I don't have to worry about configuring SharePoint all the time. See, here's the deal - when SharePoint sends emails it adds a special header that you don't normally see (in Outlook 2010, you have to open an email and hit File -> Properties to see the message headers). This special header is titled "X-Mailer" and acts like a little field and SharePoint puts inside this field "Microsoft SharePoint" something or another. So I had our exchange administrator setup a transport rule that says "If an email has an X-Mailer header with the word "SharePoint" in it and is being sent to an address that ends in @sharepoint.mydomain.com then remove the X-Mailer header". That's it!

Just to clarify - this would allow me to have two lists email each other in an infinite loop...so your SharePoint admin may not be a fan if you have a large environment and people could setup this sort of thing...only use if you have a structure in-place that would prevent that from happening :)

Friday, May 25, 2012

SharePoint 2010 LVWP Dynamic Date Filtering

Situation: You used SharePoint Designer 2010 to insert what you *thought* was a data view onto a web part page and it is actually a List View Web Part (LVWP) and you want to filter the data related to [Today]. When you click the 'Filter' button in the top-left of SPD2010, it will only let you filter to '[CurrentDate]' and doesn't give you the option to say something like '[Today]-10'.

Resolution: There are two ways to alter the core query here:
1 - No looking at the dreaded 'code' or 'CAML': Save the page in SharePoint Designer, open the page directly in your browser, modify the web part by clicking its little dropdown and clicking 'Edit Web Part' and clicking 'Edit Current View' underneath the Current View dropdown (and then fix like you would any other view...sometimes this may actually give you an error if your LVWP was being evil like mine).
2 - Must look at 'code' and 'CAML': When you look at the evil 'code' behind your data view, you will notice a section that looks like this near the top of your LVWP:
<View name="{123jk123-j123-12j1-j1k2l;3l123j}" Mobile View="TRUE" Type="HTML"....
     <Query>
          <OrderBy />
          <GroupBy />
     </Query>

If you have already filtered to '[CurrentDate]' then it will have put a section inside the <Query> that looks similar to this:
<Where>
     <Eq>
          <FieldRef Name="YourDateField"/>
          <Value Type="DateTime">
               <Today/>
          </Value>
     </Eq>
</Where>

What to fix: that lovely <Today/> piece. If you want to say something like 'Show me everything that is greater than (aka after) the last 10 days' then you would need to:
1) Add an 'OffsetDays' attribute to the Today so that it looks like this: <Today OffsetDays="-10"/>
2) Make sure that where I have "Eq", you put "Gt" (short for Greater Than) -- You could do the reverse by setting it to Lt for "Less Than" and making the OffsetDays a positive number to make it something like [Today]+7.